about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock155
-rw-r--r--RELEASES.md18
-rw-r--r--REUSE.toml2
-rw-r--r--compiler/rustc_ast/src/ast.rs2
-rw-r--r--compiler/rustc_ast/src/expand/autodiff_attrs.rs3
-rw-r--r--compiler/rustc_ast/src/token.rs14
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs33
-rw-r--r--compiler/rustc_attr_data_structures/src/stability.rs15
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs18
-rw-r--r--compiler/rustc_borrowck/messages.ftl3
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs13
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs110
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs38
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs24
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs28
-rw-r--r--compiler/rustc_borrowck/src/lib.rs14
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs7
-rw-r--r--compiler/rustc_borrowck/src/polonius/dump.rs110
-rw-r--r--compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs4
-rw-r--r--compiler/rustc_borrowck/src/prefixes.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs16
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs7
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs46
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs215
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs284
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs26
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/ty.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs33
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs18
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs20
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs7
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs6
-rw-r--r--compiler/rustc_codegen_gcc/src/debuginfo.rs4
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/int.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/builder/autodiff.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs71
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs38
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs51
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs77
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs38
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs32
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs118
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs22
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/meth.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/debuginfo.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/misc.rs4
-rw-r--r--compiler/rustc_const_eval/messages.ftl4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs11
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs7
-rw-r--r--compiler/rustc_const_eval/src/check_consts/resolver.rs3
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs9
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs9
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs45
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs53
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs36
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs11
-rw-r--r--compiler/rustc_const_eval/src/lib.rs9
-rw-r--r--compiler/rustc_const_eval/src/util/caller_location.rs9
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/thousands/mod.rs16
-rw-r--r--compiler/rustc_data_structures/src/thousands/tests.rs14
-rw-r--r--compiler/rustc_driver_impl/src/args.rs19
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs20
-rw-r--r--compiler/rustc_driver_impl/src/pretty.rs7
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs51
-rw-r--r--compiler/rustc_errors/src/emitter.rs17
-rw-r--r--compiler/rustc_errors/src/lib.rs67
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs4
-rw-r--r--compiler/rustc_hir/src/hir.rs7
-rw-r--r--compiler/rustc_hir/src/intravisit.rs3
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir/src/pat_util.rs5
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl4
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs35
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs78
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs164
-rw-r--r--compiler/rustc_hir_analysis/src/collect/dump.rs82
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs94
-rw-r--r--compiler/rustc_hir_analysis/src/delegation.rs360
-rw-r--r--compiler/rustc_hir_analysis/src/errors/pattern_types.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs46
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs45
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/variance/solve.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/variance/xform.rs22
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs38
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs36
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs42
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs142
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs11
-rw-r--r--compiler/rustc_incremental/src/lib.rs2
-rw-r--r--compiler/rustc_infer/src/infer/at.rs24
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs5
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs44
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs22
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs2
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/fudge.rs2
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/undo_log.rs2
-rw-r--r--compiler/rustc_infer/src/infer/unify_key.rs (renamed from compiler/rustc_middle/src/infer/unify_key.rs)20
-rw-r--r--compiler/rustc_interface/src/passes.rs139
-rw-r--r--compiler/rustc_interface/src/tests.rs13
-rw-r--r--compiler/rustc_lint/src/builtin.rs3
-rw-r--r--compiler/rustc_lint/src/early/diagnostics/check_cfg.rs4
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs6
-rw-r--r--compiler/rustc_lint/src/internal.rs10
-rw-r--r--compiler/rustc_lint/src/late.rs2
-rw-r--r--compiler/rustc_lint/src/multiple_supertrait_upcastable.rs2
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs10
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs8
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs17
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp222
-rw-r--r--compiler/rustc_macros/src/query.rs26
-rw-r--r--compiler/rustc_metadata/messages.ftl10
-rw-r--r--compiler/rustc_metadata/src/creader.rs97
-rw-r--r--compiler/rustc_metadata/src/errors.rs25
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs15
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs8
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs22
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs5
-rw-r--r--compiler/rustc_middle/messages.ftl7
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_middle/src/error.rs14
-rw-r--r--compiler/rustc_middle/src/hooks/mod.rs43
-rw-r--r--compiler/rustc_middle/src/infer/mod.rs1
-rw-r--r--compiler/rustc_middle/src/lint.rs40
-rw-r--r--compiler/rustc_middle/src/macros.rs31
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs4
-rw-r--r--compiler/rustc_middle/src/middle/resolve_bound_vars.rs15
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs22
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs26
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs43
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs123
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs14
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs12
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs8
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs6
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs6
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs2
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs15
-rw-r--r--compiler/rustc_middle/src/query/keys.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs34
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs81
-rw-r--r--compiler/rustc_middle/src/thir.rs57
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs3
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs5
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs47
-rw-r--r--compiler/rustc_middle/src/ty/consts/valtree.rs61
-rw-r--r--compiler/rustc_middle/src/ty/context.rs28
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs16
-rw-r--r--compiler/rustc_middle/src/ty/error.rs37
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs2
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs10
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs149
-rw-r--r--compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs2
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs18
-rw-r--r--compiler/rustc_middle/src/ty/util.rs4
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs23
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs2
-rw-r--r--compiler/rustc_middle/src/util/bug.rs6
-rw-r--r--compiler/rustc_middle/src/util/common.rs22
-rw-r--r--compiler/rustc_middle/src/util/common/tests.rs14
-rw-r--r--compiler/rustc_middle/src/util/find_self_call.rs47
-rw-r--r--compiler/rustc_middle/src/util/mod.rs4
-rw-r--r--compiler/rustc_mir_build/messages.ftl14
-rw-r--r--compiler/rustc_mir_build/src/builder/custom/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_place.rs23
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs17
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/category.rs7
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/into.rs7
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/test.rs99
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs11
-rw-r--r--compiler/rustc_mir_build/src/check_tail_calls.rs13
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs36
-rw-r--r--compiler/rustc_mir_build/src/errors.rs42
-rw-r--r--compiler/rustc_mir_build/src/lib.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs16
-rw-r--r--compiler/rustc_mir_build/src/thir/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs15
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs30
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs6
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs198
-rw-r--r--compiler/rustc_mir_transform/src/check_const_item_mutation.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_null.rs110
-rw-r--r--compiler/rustc_mir_transform/src/check_pointers.rs234
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs8
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs6
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs7
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs18
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs7
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs37
-rw-r--r--compiler/rustc_monomorphize/Cargo.toml2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs36
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs34
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/autodiff.rs121
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs6
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs5
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs6
-rw-r--r--compiler/rustc_parse_format/src/lib.rs15
-rw-r--r--compiler/rustc_passes/src/check_attr.rs1
-rw-r--r--compiler/rustc_passes/src/dead.rs18
-rw-r--r--compiler/rustc_passes/src/input_stats.rs17
-rw-r--r--compiler/rustc_passes/src/liveness.rs8
-rw-r--r--compiler/rustc_passes/src/stability.rs154
-rw-r--r--compiler/rustc_privacy/src/lib.rs24
-rw-r--r--compiler/rustc_query_impl/src/lib.rs5
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs22
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs10
-rw-r--r--compiler/rustc_session/src/code_stats.rs60
-rw-r--r--compiler/rustc_session/src/config.rs49
-rw-r--r--compiler/rustc_session/src/lib.rs3
-rw-r--r--compiler/rustc_session/src/options.rs389
-rw-r--r--compiler/rustc_session/src/parse.rs14
-rw-r--r--compiler/rustc_session/src/session.rs23
-rw-r--r--compiler/rustc_smir/src/rustc_smir/alloc.rs12
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs9
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs5
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs23
-rw-r--r--compiler/rustc_span/src/lib.rs32
-rw-r--r--compiler/rustc_span/src/symbol.rs6
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs7
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs11
-rw-r--r--compiler/rustc_target/src/asm/mod.rs13
-rw-r--r--compiler/rustc_target/src/spec/json.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs4
-rw-r--r--compiler/rustc_target/src/target_features.rs5
-rw-r--r--compiler/rustc_trait_selection/messages.ftl4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs114
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note.rs422
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs10
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs48
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs28
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs184
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs11
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs57
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs29
-rw-r--r--compiler/rustc_trait_selection/src/regions.rs80
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs9
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs496
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs527
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs82
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs44
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs175
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs33
-rw-r--r--compiler/rustc_transmute/src/lib.rs8
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs14
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs19
-rw-r--r--compiler/rustc_type_ir/src/const_kind.rs4
-rw-r--r--compiler/rustc_type_ir/src/fast_reject.rs4
-rw-r--r--compiler/rustc_type_ir/src/fold.rs2
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs5
-rw-r--r--compiler/rustc_type_ir/src/interner.rs3
-rw-r--r--compiler/rustc_type_ir/src/relate.rs4
-rw-r--r--compiler/rustc_type_ir/src/visit.rs2
-rw-r--r--compiler/stable_mir/src/mir/body.rs2
-rw-r--r--compiler/stable_mir/src/mir/pretty.rs3
-rw-r--r--compiler/stable_mir/src/mir/visit.rs5
-rw-r--r--library/alloc/src/collections/btree/node.rs4
-rw-r--r--library/alloc/src/string.rs16
-rw-r--r--library/core/src/alloc/mod.rs58
-rw-r--r--library/core/src/char/methods.rs6
-rw-r--r--library/core/src/cmp.rs170
-rw-r--r--library/core/src/hint.rs4
-rw-r--r--library/core/src/intrinsics/mod.rs7
-rw-r--r--library/core/src/macros/mod.rs28
-rw-r--r--library/core/src/marker.rs190
-rw-r--r--library/core/src/mem/maybe_uninit.rs5
-rw-r--r--library/core/src/num/f128.rs6
-rw-r--r--library/core/src/num/f16.rs6
-rw-r--r--library/core/src/num/f32.rs6
-rw-r--r--library/core/src/num/f64.rs6
-rw-r--r--library/core/src/num/mod.rs220
-rw-r--r--library/core/src/panicking.rs16
-rw-r--r--library/core/src/prelude/common.rs3
-rw-r--r--library/core/src/prelude/mod.rs10
-rw-r--r--library/core/src/primitive_docs.rs14
-rw-r--r--library/core/src/ptr/const_ptr.rs6
-rw-r--r--library/core/src/ptr/mut_ptr.rs5
-rw-r--r--library/core/src/slice/rotate.rs334
-rw-r--r--library/core/src/slice/sort/stable/drift.rs4
-rw-r--r--library/core/src/slice/sort/stable/mod.rs24
-rw-r--r--library/core/src/slice/sort/stable/quicksort.rs2
-rw-r--r--library/core/src/str/mod.rs3
-rw-r--r--library/core/src/sync/atomic.rs18
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/std/src/fs.rs57
-rw-r--r--library/std/src/io/pipe/tests.rs2
-rw-r--r--library/std/src/prelude/mod.rs10
-rw-r--r--library/std/src/process.rs12
-rw-r--r--library/std/src/sync/once_lock.rs4
-rw-r--r--library/std/src/sync/poison/mutex.rs32
-rw-r--r--library/std/src/sync/poison/once.rs6
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs50
-rw-r--r--library/std/src/sys/pal/uefi/process.rs7
-rw-r--r--library/std/src/sys/path/mod.rs8
-rw-r--r--library/std/src/sys/path/uefi.rs105
-rw-r--r--license-metadata.json6
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs9
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs3
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs28
-rw-r--r--src/bootstrap/src/core/config/config.rs9
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile5
-rw-r--r--src/ci/github-actions/jobs.yml25
-rwxr-xr-xsrc/ci/scripts/free-disk-space.sh94
-rw-r--r--src/doc/rustc-dev-guide/.github/workflows/ci.yml6
-rw-r--r--src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml4
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-example.rs2
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs2
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs8
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/src/about-this-guide.md1
-rw-r--r--src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md2
-rw-r--r--src/doc/rustc-dev-guide/src/building/new-target.md5
-rw-r--r--src/doc/rustc-dev-guide/src/compiler-debugging.md2
-rw-r--r--src/doc/rustc-dev-guide/src/conventions.md2
-rw-r--r--src/doc/rustc-dev-guide/src/diagnostics.md2
-rw-r--r--src/doc/rustc-dev-guide/src/early_late_parameters.md64
-rw-r--r--src/doc/rustc-dev-guide/src/getting-started.md4
-rw-r--r--src/doc/rustc-dev-guide/src/rustdoc.md9
-rw-r--r--src/doc/rustc-dev-guide/src/solve/significant-changes.md2
-rw-r--r--src/doc/rustc-dev-guide/src/traits/implied-bounds.md4
-rw-r--r--src/doc/rustc/src/profile-guided-optimization.md2
-rw-r--r--src/doc/rustc/src/target-tier-policy.md11
-rw-r--r--src/doc/rustdoc/src/unstable-features.md64
-rw-r--r--src/doc/style-guide/src/editions.md4
-rw-r--r--src/doc/style-guide/src/expressions.md55
-rw-r--r--src/doc/unstable-book/src/compiler-flags/autodiff.md23
-rw-r--r--src/doc/unstable-book/src/compiler-flags/dwarf-version.md4
-rw-r--r--src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md19
-rw-r--r--src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md19
-rw-r--r--src/librustdoc/build.rs5
-rw-r--r--src/librustdoc/clean/types.rs12
-rw-r--r--src/librustdoc/clean/utils.rs9
-rw-r--r--src/librustdoc/config.rs69
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/librustdoc/doctest.rs51
-rw-r--r--src/librustdoc/doctest/extracted.rs141
-rw-r--r--src/librustdoc/html/render/span_map.rs26
-rw-r--r--src/librustdoc/html/static/COPYRIGHT.txt2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css51
-rwxr-xr-xsrc/librustdoc/html/static/fonts/FiraMono-Medium.woff2bin0 -> 64572 bytes
-rwxr-xr-xsrc/librustdoc/html/static/fonts/FiraMono-Regular.woff2bin0 -> 64868 bytes
-rwxr-xr-xsrc/librustdoc/html/static/fonts/FiraSans-Italic.woff2bin0 -> 136300 bytes
-rwxr-xr-xsrc/librustdoc/html/static/fonts/FiraSans-MediumItalic.woff2bin0 -> 140588 bytes
-rw-r--r--src/librustdoc/html/static/fonts/SourceSerif4-Semibold.ttf.woff2bin0 -> 80732 bytes
-rw-r--r--src/librustdoc/html/static/js/README.md10
-rw-r--r--src/librustdoc/html/static/js/externs.js270
-rw-r--r--src/librustdoc/html/static/js/main.js345
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts387
-rw-r--r--src/librustdoc/html/static/js/scrape-examples.js3
-rw-r--r--src/librustdoc/html/static/js/search.js1201
-rw-r--r--src/librustdoc/html/static/js/settings.js14
-rw-r--r--src/librustdoc/html/static/js/src-script.js3
-rw-r--r--src/librustdoc/html/static/js/storage.js101
-rw-r--r--src/librustdoc/html/static/js/tsconfig.json15
-rw-r--r--src/librustdoc/html/static_files.rs5
-rw-r--r--src/librustdoc/html/templates/page.html2
-rw-r--r--src/librustdoc/lib.rs13
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md2
-rw-r--r--src/tools/clippy/book/src/development/common_tools_writing_lints.md6
-rw-r--r--src/tools/clippy/book/src/development/macro_expansions.md6
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_range.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/as_conversions.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/ctfe.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/else_if_without_else.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_nesting.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_range_patterns.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_empty.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_if.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/non_canonical_impls.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/raw_strings.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_field_names.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/single_call_fn.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/uninhabited_references.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_result_ok.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_trait_names.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/visibility.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs25
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/src/driver.rs7
-rw-r--r--src/tools/compiletest/src/directive-list.rs5
-rw-r--r--src/tools/compiletest/src/header.rs8
-rw-r--r--src/tools/compiletest/src/runtest.rs4
-rw-r--r--src/tools/compiletest/src/runtest/rustdoc_json.rs3
m---------src/tools/enzyme0
-rw-r--r--src/tools/miri/Cargo.lock96
-rw-r--r--src/tools/miri/Cargo.toml6
-rwxr-xr-xsrc/tools/miri/ci/ci.sh4
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs2
-rw-r--r--src/tools/miri/src/alloc_addresses/reuse_pool.rs8
-rw-r--r--src/tools/miri/src/bin/miri.rs12
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs22
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs20
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs40
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs2
-rw-r--r--src/tools/miri/src/concurrency/sync.rs64
-rw-r--r--src/tools/miri/src/concurrency/thread.rs2
-rw-r--r--src/tools/miri/src/eval.rs6
-rw-r--r--src/tools/miri/src/helpers.rs65
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs6
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs5
-rw-r--r--src/tools/miri/src/lib.rs5
-rw-r--r--src/tools/miri/src/machine.rs28
-rw-r--r--src/tools/miri/src/math.rs20
-rw-r--r--src/tools/miri/src/operator.rs9
-rw-r--r--src/tools/miri/src/shims/alloc.rs22
-rw-r--r--src/tools/miri/src/shims/backtrace.rs41
-rw-r--r--src/tools/miri/src/shims/extern_static.rs8
-rw-r--r--src/tools/miri/src/shims/files.rs101
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs22
-rw-r--r--src/tools/miri/src/shims/panic.rs11
-rw-r--r--src/tools/miri/src/shims/time.rs15
-rw-r--r--src/tools/miri/src/shims/unix/android/thread.rs11
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs67
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs95
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs6
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs88
-rw-r--r--src/tools/miri/src/shims/unix/linux/mem.rs10
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/eventfd.rs37
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/sync.rs52
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/syscall.rs13
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs88
-rw-r--r--src/tools/miri/src/shims/unix/macos/sync.rs218
-rw-r--r--src/tools/miri/src/shims/unix/mem.rs16
-rw-r--r--src/tools/miri/src/shims/unix/solarish/foreign_items.rs8
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs15
-rw-r--r--src/tools/miri/src/shims/unix/unnamed_socket.rs60
-rw-r--r--src/tools/miri/src/shims/windows/env.rs2
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs22
-rw-r--r--src/tools/miri/src/shims/windows/sync.rs31
-rw-r--r--src/tools/miri/src/shims/windows/thread.rs2
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock31
-rw-r--r--src/tools/miri/test_dependencies/Cargo.toml3
-rw-r--r--src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr15
-rw-r--r--src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs7
-rw-r--r--src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.rs17
-rw-r--r--src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.stderr15
-rw-r--r--src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.rs16
-rw-r--r--src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.stderr15
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs276
-rw-r--r--src/tools/miri/tests/pass-dep/getrandom.rs4
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs24
-rw-r--r--src/tools/miri/tests/pass/dyn-upcast.rs52
-rw-r--r--src/tools/miri/tests/pass/dyn-upcast.stdout2
-rw-r--r--src/tools/miri/tests/pass/float.rs28
-rw-r--r--src/tools/miri/tests/ui.rs73
-rw-r--r--src/tools/opt-dist/src/main.rs12
-rw-r--r--src/tools/run-make-support/src/command.rs6
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs22
-rw-r--r--src/tools/run-make-support/src/lib.rs10
-rw-r--r--src/tools/run-make-support/src/symbols.rs34
-rw-r--r--src/tools/run-make-support/src/targets.rs6
-rw-r--r--src/tools/rust-analyzer/Cargo.lock7
-rw-r--r--src/tools/rust-analyzer/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs258
-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/nameres/collector.rs72
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs74
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs49
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs106
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs45
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs131
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs74
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs137
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs90
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs151
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs72
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/config.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/lib.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs28
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs83
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt33
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs49
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs104
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs85
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs77
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs301
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs73
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs49
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs2
-rw-r--r--src/tools/rust-analyzer/crates/intern/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol.rs37
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs11
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs18
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/project_json.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs41
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs25
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs5
-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/lib.rs3
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs135
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs12
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs17
-rw-r--r--src/tools/rust-analyzer/docs/dev/README.md18
-rw-r--r--src/tools/rust-analyzer/docs/dev/lsp-extensions.md2
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc10
-rw-r--r--src/tools/rust-analyzer/docs/user/manual.adoc90
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json20
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts9
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/msg.rs6
-rw-r--r--src/tools/rustbook/Cargo.lock52
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/rustfmt/src/bin/main.rs9
-rw-r--r--src/tools/rustfmt/src/config/mod.rs2
-rw-r--r--src/tools/rustfmt/src/config/options.rs4
-rw-r--r--src/tools/rustfmt/src/parse/session.rs16
-rw-r--r--src/tools/rustfmt/tests/target/configs/style_edition/overflow_delim_expr_2024.rs73
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt2
-rw-r--r--src/tools/tidy/src/bins.rs2
-rw-r--r--tests/assembly/small_data_threshold.rs60
-rw-r--r--tests/codegen/addr-of-mutate.rs6
-rw-r--r--tests/codegen/asm/bpf-clobbers.rs31
-rw-r--r--tests/codegen/cast-target-abi.rs2
-rw-r--r--tests/codegen/float/f128.rs31
-rw-r--r--tests/codegen/function-arguments.rs4
-rw-r--r--tests/codegen/i128-x86-align.rs21
-rw-r--r--tests/codegen/issues/issue-136329-optnone-noinline.rs21
-rw-r--r--tests/codegen/lib-optimizations/slice_rotate.rs30
-rw-r--r--tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs4
-rw-r--r--tests/codegen/packed.rs4
-rw-r--r--tests/codegen/riscv-abi/riscv64-lp64d-abi.rs2
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs8
-rw-r--r--tests/codegen/wasm_exceptions.rs2
-rw-r--r--tests/crashes/131102.rs4
-rw-r--r--tests/crashes/131103.rs6
-rw-r--r--tests/crashes/135210.rs8
-rw-r--r--tests/mir-opt/null_check_references.rs16
-rw-r--r--tests/mir-opt/pattern_types.main.PreCodegen.after.mir15
-rw-r--r--tests/mir-opt/pattern_types.rs12
-rw-r--r--tests/run-make/symbol-mangling-hashed/Makefile48
-rw-r--r--tests/run-make/symbol-mangling-hashed/b_bin.rs9
-rw-r--r--tests/run-make/symbol-mangling-hashed/b_dylib.rs9
-rw-r--r--tests/run-make/symbol-mangling-hashed/default_bin.rs9
-rw-r--r--tests/run-make/symbol-mangling-hashed/default_dylib.rs9
-rw-r--r--tests/run-make/symbol-mangling-hashed/hashed_dylib.rs (renamed from tests/run-make/symbol-mangling-hashed/a_dylib.rs)2
-rw-r--r--tests/run-make/symbol-mangling-hashed/hashed_rlib.rs (renamed from tests/run-make/symbol-mangling-hashed/a_rlib.rs)2
-rw-r--r--tests/run-make/symbol-mangling-hashed/rmake.rs108
-rw-r--r--tests/run-make/target-specs/require-explicit-cpu.json11
-rw-r--r--tests/run-make/target-specs/rmake.rs13
-rw-r--r--tests/run-make/translation/Makefile78
-rw-r--r--tests/run-make/translation/rmake.rs194
-rw-r--r--tests/rustdoc-gui/font-serif-change.goml31
-rw-r--r--tests/rustdoc-gui/settings.goml8
-rw-r--r--tests/rustdoc-ui/coverage/html.stderr2
-rw-r--r--tests/rustdoc-ui/doctest-output.rs1
-rw-r--r--tests/rustdoc-ui/doctest-output.stderr2
-rw-r--r--tests/rustdoc-ui/extract-doctests.rs15
-rw-r--r--tests/rustdoc-ui/extract-doctests.stdout1
-rw-r--r--tests/rustdoc-ui/intra-doc/auxiliary/issue-103463-aux.rs (renamed from tests/rustdoc/intra-doc/auxiliary/issue-103463-aux.rs)0
-rw-r--r--tests/rustdoc-ui/intra-doc/ice-extern-trait-local-impl-104145.rs (renamed from tests/rustdoc/intra-doc/issue-104145.rs)3
-rw-r--r--tests/rustdoc-ui/intra-doc/ice-priv-use-103463.rs (renamed from tests/rustdoc/intra-doc/issue-103463.rs)3
-rw-r--r--tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr2
-rw-r--r--tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr2
-rw-r--r--tests/rustdoc/inline_cross/doc-hidden-broken-link-28480.rs (renamed from tests/rustdoc/inline_cross/issue-28480.rs)5
-rw-r--r--tests/rustdoc/inline_cross/doc-reachability-impl-31948-1.rs (renamed from tests/rustdoc/inline_cross/issue-31948-1.rs)13
-rw-r--r--tests/rustdoc/inline_cross/doc-reachability-impl-31948-2.rs (renamed from tests/rustdoc/inline_cross/issue-31948-2.rs)13
-rw-r--r--tests/rustdoc/inline_cross/doc-reachability-impl-31948.rs (renamed from tests/rustdoc/inline_cross/issue-31948.rs)17
-rw-r--r--tests/rustdoc/inline_cross/impl-dyn-trait-32881.rs (renamed from tests/rustdoc/inline_cross/issue-32881.rs)5
-rw-r--r--tests/rustdoc/inline_cross/impl-ref-33113.rs (renamed from tests/rustdoc/inline_cross/issue-33113.rs)5
-rw-r--r--tests/rustdoc/inline_cross/rustc-private-76736-1.rs (renamed from tests/rustdoc/inline_cross/issue-76736-1.rs)2
-rw-r--r--tests/rustdoc/inline_cross/rustc-private-76736-2.rs (renamed from tests/rustdoc/inline_cross/issue-76736-2.rs)2
-rw-r--r--tests/rustdoc/inline_cross/rustc-private-76736-3.rs (renamed from tests/rustdoc/inline_cross/issue-76736-3.rs)2
-rw-r--r--tests/rustdoc/inline_cross/rustc-private-76736-4.rs (renamed from tests/rustdoc/inline_cross/issue-76736-4.rs)2
-rw-r--r--tests/rustdoc/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html (renamed from tests/rustdoc/inline_cross/issue-24183.method_no_where_self_sized.html)0
-rw-r--r--tests/rustdoc/inline_cross/self-sized-bounds-24183.rs (renamed from tests/rustdoc/inline_cross/issue-24183.rs)1
-rw-r--r--tests/rustdoc/inline_local/doc-no-inline-32343.rs (renamed from tests/rustdoc/inline_local/issue-32343.rs)13
-rw-r--r--tests/rustdoc/inline_local/fully-stable-path-is-better.rs4
-rw-r--r--tests/rustdoc/inline_local/pub-re-export-28537.rs (renamed from tests/rustdoc/inline_local/issue-28537.rs)7
-rw-r--r--tests/rustdoc/intra-doc/enum-self-82209.rs (renamed from tests/rustdoc/intra-doc/issue-82209.rs)2
-rw-r--r--tests/rustdoc/intra-doc/link-same-name-different-disambiguator-108459.rs (renamed from tests/rustdoc/intra-doc/issue-108459.rs)11
-rw-r--r--tests/rustdoc/intra-doc/same-name-different-crates-66159.rs (renamed from tests/rustdoc/intra-doc/issue-66159.rs)5
-rw-r--r--tests/rustdoc/stability.rs2
-rw-r--r--tests/ui-fulldeps/obtain-borrowck.rs1
-rw-r--r--tests/ui/abi/segfault-no-out-of-stack.rs1
-rw-r--r--tests/ui/array-slice-vec/driftsort-off-by-one-issue-136103.rs10
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv32e.stderr66
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv32gc.stderr26
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv32i.stderr34
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr30
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv64gc.stderr26
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv64imac.stderr34
-rw-r--r--tests/ui/asm/riscv/bad-reg.rs2
-rw-r--r--tests/ui/associated-consts/associated-const-in-trait.stderr4
-rw-r--r--tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr2
-rw-r--r--tests/ui/associated-item/issue-48027.stderr2
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.current.stderr2
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.next.stderr2
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.rs2
-rw-r--r--tests/ui/async-await/async-fn/dyn-pos.stderr2
-rw-r--r--tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr20
-rw-r--r--tests/ui/async-await/in-trait/dyn-compatibility.stderr2
-rw-r--r--tests/ui/async-await/inference_var_self_argument.stderr2
-rw-r--r--tests/ui/async-await/issue-98634.rs6
-rw-r--r--tests/ui/async-await/issue-98634.stderr6
-rw-r--r--tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.rs46
-rw-r--r--tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.stderr89
-rw-r--r--tests/ui/borrowck/issue-93093.rs2
-rw-r--r--tests/ui/borrowck/issue-93093.stderr2
-rw-r--r--tests/ui/borrowck/trait-impl-argument-difference-ice.stderr4
-rw-r--r--tests/ui/closures/return-type-doesnt-match-bound.rs25
-rw-r--r--tests/ui/closures/return-type-doesnt-match-bound.stderr37
-rw-r--r--tests/ui/coercion/coerce-expect-unsized-ascribed.stderr6
-rw-r--r--tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr2
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr4
-rw-r--r--tests/ui/const-generics/bad-subst-const-kind.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-102768.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr2
-rw-r--r--tests/ui/const-generics/issues/index_array_bad_type.rs13
-rw-r--r--tests/ui/const-generics/issues/index_array_bad_type.stderr18
-rw-r--r--tests/ui/const-generics/issues/issue-88119.stderr34
-rw-r--r--tests/ui/const-generics/transmute-fail.stderr4
-rw-r--r--tests/ui/const-generics/type_mismatch.stderr2
-rw-r--r--tests/ui/const-ptr/forbidden_slices.stderr4
-rw-r--r--tests/ui/consts/bad-array-size-in-type-err.rs11
-rw-r--r--tests/ui/consts/bad-array-size-in-type-err.stderr47
-rw-r--r--tests/ui/consts/const-eval/parse_ints.stderr12
-rw-r--r--tests/ui/consts/const-slice-array-deref.rs9
-rw-r--r--tests/ui/consts/const-slice-array-deref.stderr33
-rw-r--r--tests/ui/consts/large_const_alloc.rs2
-rw-r--r--tests/ui/consts/large_const_alloc.stderr4
-rw-r--r--tests/ui/consts/offset_from_ub.rs10
-rw-r--r--tests/ui/consts/offset_from_ub.stderr14
-rw-r--r--tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs2
-rw-r--r--tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr2
-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/diagnostic-width/E0271.ascii.stderr8
-rw-r--r--tests/ui/diagnostic-width/E0271.rs4
-rw-r--r--tests/ui/diagnostic-width/E0271.unicode.stderr8
-rw-r--r--tests/ui/diagnostic-width/long-E0308.ascii.stderr36
-rw-r--r--tests/ui/diagnostic-width/long-E0308.rs4
-rw-r--r--tests/ui/diagnostic-width/long-E0308.unicode.stderr36
-rw-r--r--tests/ui/diagnostic-width/long-e0277.rs15
-rw-r--r--tests/ui/diagnostic-width/long-e0277.stderr23
-rw-r--r--tests/ui/diagnostic-width/non-copy-type-moved.rs4
-rw-r--r--tests/ui/diagnostic-width/non-copy-type-moved.stderr6
-rw-r--r--tests/ui/diagnostic-width/secondary-label-with-long-type.rs6
-rw-r--r--tests/ui/diagnostic-width/secondary-label-with-long-type.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr12
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs4
-rw-r--r--tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs9
-rw-r--r--tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr59
-rw-r--r--tests/ui/did_you_mean/issue-38147-1.stderr2
-rw-r--r--tests/ui/did_you_mean/issue-39544.stderr6
-rw-r--r--tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr2
-rw-r--r--tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr6
-rw-r--r--tests/ui/dyn-compatibility/associated-consts.curr.stderr4
-rw-r--r--tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr2
-rw-r--r--tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr2
-rw-r--r--tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr4
-rw-r--r--tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr2
-rw-r--r--tests/ui/dyn-compatibility/bounds.stderr2
-rw-r--r--tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr2
-rw-r--r--tests/ui/dyn-compatibility/generics.curr.stderr10
-rw-r--r--tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr4
-rw-r--r--tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr4
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr6
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self.curr.stderr8
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr4
-rw-r--r--tests/ui/dyn-compatibility/missing-assoc-type.stderr2
-rw-r--r--tests/ui/dyn-compatibility/no-static.curr.stderr6
-rw-r--r--tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr2
-rw-r--r--tests/ui/dyn-compatibility/sized-2.curr.stderr4
-rw-r--r--tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr2
-rw-r--r--tests/ui/dyn-compatibility/sized.curr.stderr4
-rw-r--r--tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr2
-rw-r--r--tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr2
-rw-r--r--tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr2
-rw-r--r--tests/ui/dyn-compatibility/taint-const-eval.curr.stderr6
-rw-r--r--tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr2
-rw-r--r--tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr6
-rw-r--r--tests/ui/error-codes/E0038.stderr4
-rw-r--r--tests/ui/error-codes/E0789.rs2
-rw-r--r--tests/ui/error-emitter/E0308-clarification.rs16
-rw-r--r--tests/ui/error-emitter/E0308-clarification.svg97
-rw-r--r--tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr6
-rw-r--r--tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr10
-rw-r--r--tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs16
-rw-r--r--tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr66
-rw-r--r--tests/ui/fn/fn-pointer-mismatch.stderr2
-rw-r--r--tests/ui/force-inlining/cast.stderr4
-rw-r--r--tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr2
-rw-r--r--tests/ui/generic-associated-types/gat-in-trait-path.stderr6
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr4
-rw-r--r--tests/ui/generic-associated-types/issue-67510-pass.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-67510.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-71176.stderr6
-rw-r--r--tests/ui/generic-associated-types/issue-76535.stderr4
-rw-r--r--tests/ui/generic-associated-types/issue-78671.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-79422.stderr4
-rw-r--r--tests/ui/generic-associated-types/issue-90014-tait2.rs3
-rw-r--r--tests/ui/generic-associated-types/issue-90014-tait2.stderr2
-rw-r--r--tests/ui/generic-associated-types/missing_lifetime_args.stderr2
-rw-r--r--tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr2
-rw-r--r--tests/ui/generic-associated-types/trait-objects.stderr6
-rw-r--r--tests/ui/generic-const-items/def-site-eval.fail.stderr11
-rw-r--r--tests/ui/generic-const-items/def-site-eval.rs16
-rw-r--r--tests/ui/generic-const-items/def-site-mono.rs13
-rw-r--r--tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr2
-rw-r--r--tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs6
-rw-r--r--tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr37
-rw-r--r--tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr4
-rw-r--r--tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr8
-rw-r--r--tests/ui/impl-trait/impl-trait-in-macro.stderr4
-rw-r--r--tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr5
-rw-r--r--tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr6
-rw-r--r--tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.rs14
-rw-r--r--tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.stderr17
-rw-r--r--tests/ui/impl-trait/in-trait/dyn-compatibility.stderr8
-rw-r--r--tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr2
-rw-r--r--tests/ui/impl-trait/universal-two-impl-traits.stderr4
-rw-r--r--tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs3
-rw-r--r--tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.stderr10
-rw-r--r--tests/ui/infinite/infinite-instantiation.rs3
-rw-r--r--tests/ui/infinite/infinite-instantiation.stderr6
-rw-r--r--tests/ui/intrinsics/const-eval-select-bad.rs2
-rw-r--r--tests/ui/intrinsics/const-eval-select-bad.stderr2
-rw-r--r--tests/ui/issues/issue-18959.stderr10
-rw-r--r--tests/ui/issues/issue-19380.stderr6
-rw-r--r--tests/ui/issues/issue-26056.stderr2
-rw-r--r--tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs3
-rw-r--r--tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr6
-rw-r--r--tests/ui/issues/issue-50781.stderr6
-rw-r--r--tests/ui/issues/issue-67552.rs3
-rw-r--r--tests/ui/issues/issue-67552.stderr6
-rw-r--r--tests/ui/issues/issue-8727.rs3
-rw-r--r--tests/ui/issues/issue-8727.stderr8
-rw-r--r--tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr4
-rw-r--r--tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr2
-rw-r--r--tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs9
-rw-r--r--tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr20
-rw-r--r--tests/ui/lazy-type-alias/def-site-predicates-wf.rs13
-rw-r--r--tests/ui/lazy-type-alias/def-site-predicates-wf.stderr23
-rw-r--r--tests/ui/lint/dead-code/lint-dead-code-1.rs2
-rw-r--r--tests/ui/lint/dead-code/lint-dead-code-1.stderr14
-rw-r--r--tests/ui/lint/issue-106991.rs2
-rw-r--r--tests/ui/lint/issue-106991.stderr2
-rw-r--r--tests/ui/liveness/liveness-unused.rs6
-rw-r--r--tests/ui/liveness/liveness-unused.stderr28
-rw-r--r--tests/ui/mir/null/addrof_null.rs14
-rw-r--r--tests/ui/mir/null/borrowed_mut_null.rs8
-rw-r--r--tests/ui/mir/null/borrowed_null.rs8
-rw-r--r--tests/ui/mir/null/null_lhs.rs10
-rw-r--r--tests/ui/mir/null/null_rhs.rs10
-rw-r--r--tests/ui/mir/null/place_without_read.rs10
-rw-r--r--tests/ui/mir/null/two_pointers.rs12
-rw-r--r--tests/ui/mir/null/zero_sized_access.rs15
-rw-r--r--tests/ui/mut/mutable-class-fields-2.stderr2
-rw-r--r--tests/ui/never_type/fallback-closure-wrap.fallback.stderr15
-rw-r--r--tests/ui/never_type/fallback-closure-wrap.rs2
-rw-r--r--tests/ui/pattern/issue-110508.rs8
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr79
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs40
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr69
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr25
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr (renamed from tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr)4
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic2024.stderr (renamed from tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr)0
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs6
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural2024.stderr (renamed from tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr)0
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic2024.stderr (renamed from tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr)21
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs29
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural2024.stderr (renamed from tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr)16
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2024.stderr (renamed from tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr)68
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs164
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr283
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr89
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr228
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr70
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs97
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr42
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr141
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed33
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed45
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.stderr (renamed from tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr)20
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs32
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr58
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed33
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed45
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.stderr (renamed from tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr)10
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs2
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs126
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr260
-rw-r--r--tests/ui/privacy/sysroot-private.default.stderr8
-rw-r--r--tests/ui/privacy/sysroot-private.rs1
-rw-r--r--tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr8
-rw-r--r--tests/ui/recursion/recursion.rs3
-rw-r--r--tests/ui/recursion/recursion.stderr6
-rw-r--r--tests/ui/resolve/issue-3907-2.stderr2
-rw-r--r--tests/ui/sanitizer/asan_odr_windows.rs (renamed from tests/ui/asan-odr-win/asan_odr_windows.rs)0
-rw-r--r--tests/ui/sanitizer/auxiliary/asan_odr_win-2.rs (renamed from tests/ui/asan-odr-win/auxiliary/asan_odr_win-2.rs)0
-rw-r--r--tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr4
-rw-r--r--tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr2
-rw-r--r--tests/ui/stability-attribute/allowed-through-unstable.rs3
-rw-r--r--tests/ui/stability-attribute/allowed-through-unstable.stderr8
-rw-r--r--tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs6
-rw-r--r--tests/ui/statics/unsizing-wfcheck-issue-127299.stderr6
-rw-r--r--tests/ui/suggestions/box-future-wrong-output.stderr2
-rw-r--r--tests/ui/suggestions/dont-suggest-boxing-async-closure-body.rs2
-rw-r--r--tests/ui/suggestions/dont-suggest-boxing-async-closure-body.stderr2
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr4
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr4
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr4
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr2
-rw-r--r--tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr2
-rw-r--r--tests/ui/suggestions/issue-107860.stderr2
-rw-r--r--tests/ui/suggestions/issue-116434-2015.stderr4
-rw-r--r--tests/ui/suggestions/issue-98500.stderr2
-rw-r--r--tests/ui/suggestions/suggest-ref-mut.rs2
-rw-r--r--tests/ui/suggestions/suggest-ref-mut.stderr2
-rw-r--r--tests/ui/target_modifiers/auxiliary/default_reg_struct_return.rs20
-rw-r--r--tests/ui/target_modifiers/auxiliary/wrong_regparm.rs20
-rw-r--r--tests/ui/target_modifiers/auxiliary/wrong_regparm_and_ret.rs20
-rw-r--r--tests/ui/target_modifiers/defaults_check.error.stderr13
-rw-r--r--tests/ui/target_modifiers/defaults_check.rs27
-rw-r--r--tests/ui/target_modifiers/incompatible_regparm.allow_no_value.stderr2
-rw-r--r--tests/ui/target_modifiers/incompatible_regparm.error_generated.stderr13
-rw-r--r--tests/ui/target_modifiers/incompatible_regparm.rs23
-rw-r--r--tests/ui/target_modifiers/two_flags.rs23
-rw-r--r--tests/ui/target_modifiers/two_flags.unknown_allowed.stderr8
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout52
-rw-r--r--tests/ui/traits/alias/generic-default-in-dyn.stderr4
-rw-r--r--tests/ui/traits/alias/object-fail.stderr2
-rw-r--r--tests/ui/traits/alias/self-in-const-generics.stderr2
-rw-r--r--tests/ui/traits/alias/self-in-generics.stderr2
-rw-r--r--tests/ui/traits/const-traits/enforce-deref-on-adjust.rs28
-rw-r--r--tests/ui/traits/ice-with-dyn-pointee-errors.stderr2
-rw-r--r--tests/ui/traits/issue-20692.stderr4
-rw-r--r--tests/ui/traits/issue-28576.stderr2
-rw-r--r--tests/ui/traits/issue-38404.stderr6
-rw-r--r--tests/ui/traits/issue-38604.stderr4
-rw-r--r--tests/ui/traits/issue-72410.stderr2
-rw-r--r--tests/ui/traits/item-privacy.stderr2
-rw-r--r--tests/ui/traits/missing-for-type-in-impl.e2015.stderr2
-rw-r--r--tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr4
-rw-r--r--tests/ui/traits/next-solver/specialization-transmute.stderr7
-rw-r--r--tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr6
-rw-r--r--tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs (renamed from tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs)0
-rw-r--r--tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr (renamed from tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr)0
-rw-r--r--tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.rs (renamed from tests/ui/type-alias-impl-trait/non-lifetime-binder.rs)0
-rw-r--r--tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.stderr (renamed from tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr)0
-rw-r--r--tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr4
-rw-r--r--tests/ui/traits/object/macro-matcher.stderr2
-rw-r--r--tests/ui/traits/object/pretty.stderr4
-rw-r--r--tests/ui/traits/object/print_vtable_sizes.rs62
-rw-r--r--tests/ui/traits/object/print_vtable_sizes.stdout11
-rw-r--r--tests/ui/traits/object/safety.stderr4
-rw-r--r--tests/ui/traits/on_unimplemented_long_types.rs3
-rw-r--r--tests/ui/traits/on_unimplemented_long_types.stderr6
-rw-r--r--tests/ui/traits/sized-coniductive.rs14
-rw-r--r--tests/ui/traits/solver-cycles/129541-recursive-struct-and-array-impl.rs23
-rw-r--r--tests/ui/traits/solver-cycles/129541-recursive-struct.rs5
-rw-r--r--tests/ui/traits/test-2.stderr6
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.rs27
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.stderr26
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs26
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout1
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs37
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr26
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs34
-rw-r--r--tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.run.stdout1
-rw-r--r--tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs30
-rw-r--r--tests/ui/traits/vtable/multiple-markers.rs33
-rw-r--r--tests/ui/traits/vtable/multiple-markers.stderr32
-rw-r--r--tests/ui/traits/vtable/vtable-diamond.rs31
-rw-r--r--tests/ui/traits/vtable/vtable-diamond.stderr45
-rw-r--r--tests/ui/traits/vtable/vtable-dyn-incompatible.rs7
-rw-r--r--tests/ui/traits/vtable/vtable-dyn-incompatible.stderr16
-rw-r--r--tests/ui/traits/vtable/vtable-multi-level.rs99
-rw-r--r--tests/ui/traits/vtable/vtable-multi-level.stderr197
-rw-r--r--tests/ui/traits/vtable/vtable-multiple.rs22
-rw-r--r--tests/ui/traits/vtable/vtable-multiple.stderr33
-rw-r--r--tests/ui/traits/vtable/vtable-vacant.rs15
-rw-r--r--tests/ui/traits/vtable/vtable-vacant.stderr22
-rw-r--r--tests/ui/type-alias-impl-trait/issue-98604.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-98604.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-98608.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-98608.stderr2
-rw-r--r--tests/ui/type/pattern_types/chars.rs12
-rw-r--r--tests/ui/type/pattern_types/nested.rs26
-rw-r--r--tests/ui/type/pattern_types/nested.stderr62
-rw-r--r--tests/ui/type/pattern_types/pattern_type_mismatch.rs20
-rw-r--r--tests/ui/type/pattern_types/pattern_type_mismatch.stderr31
-rw-r--r--tests/ui/type/pattern_types/reverse_range.rs14
-rw-r--r--tests/ui/type/pattern_types/reverse_range.stderr17
-rw-r--r--tests/ui/type/pattern_types/transmute.rs32
-rw-r--r--tests/ui/type/pattern_types/transmute.stderr21
-rw-r--r--tests/ui/type/pattern_types/validity.rs37
-rw-r--r--tests/ui/type/pattern_types/validity.stderr79
-rw-r--r--tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr2
-rw-r--r--tests/ui/type_length_limit.rs3
-rw-r--r--tests/ui/type_length_limit.stderr4
-rw-r--r--tests/ui/typeck/issue-107775.stderr4
-rw-r--r--tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr2
-rw-r--r--tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr2
-rw-r--r--tests/ui/typeck/path-to-method-sugg-unresolved-expr.rs4
-rw-r--r--tests/ui/typeck/return_type_containing_closure.rs2
-rw-r--r--tests/ui/typeck/return_type_containing_closure.stderr2
-rw-r--r--tests/ui/union/union-derive-eq.next.stderr2
-rw-r--r--tests/ui/unsafe-binders/expr.rs4
-rw-r--r--tests/ui/unsafe-binders/expr.stderr16
-rw-r--r--tests/ui/unsafe-binders/mismatch.rs17
-rw-r--r--tests/ui/unsafe-binders/mismatch.stderr47
-rw-r--r--tests/ui/unsafe-binders/moves.rs41
-rw-r--r--tests/ui/unsafe-binders/moves.stderr85
-rw-r--r--tests/ui/wf/issue-87495.stderr2
-rw-r--r--tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr6
-rw-r--r--tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr6
-rw-r--r--tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr4
-rw-r--r--tests/ui/wf/wf-dyn-incompatible.stderr2
-rw-r--r--tests/ui/wf/wf-fn-where-clause.stderr2
-rw-r--r--tests/ui/wf/wf-normalization-sized.next.stderr6
-rw-r--r--tests/ui/wf/wf-trait-default-fn-ret.rs3
-rw-r--r--tests/ui/wf/wf-trait-default-fn-ret.stderr4
-rw-r--r--tests/ui/wf/wf-trait-fn-arg.next.stderr5
-rw-r--r--tests/ui/wf/wf-trait-fn-ret.next.stderr5
-rw-r--r--tests/ui/wf/wf-trait-fn-where-clause.next.stderr5
-rw-r--r--triagebot.toml2
1193 files changed, 18423 insertions, 10066 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 04bb96be369..77653530925 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -43,7 +43,7 @@ dependencies = [
  "cfg-if",
  "once_cell",
  "version_check",
- "zerocopy",
+ "zerocopy 0.7.35",
 ]
 
 [[package]]
@@ -567,7 +567,7 @@ dependencies = [
  "termize",
  "tokio",
  "toml 0.7.8",
- "ui_test",
+ "ui_test 0.26.5",
  "walkdir",
 ]
 
@@ -1442,7 +1442,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.13.3+wasi-0.2.2",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -2342,18 +2354,18 @@ dependencies = [
  "chrono-tz",
  "colored",
  "directories",
- "getrandom",
+ "getrandom 0.3.1",
  "libc",
  "libffi",
  "libloading",
  "measureme",
- "rand",
+ "rand 0.9.0",
  "regex",
  "rustc_version",
  "smallvec",
  "tempfile",
  "tikv-jemalloc-sys",
- "ui_test",
+ "ui_test 0.28.0",
  "windows-sys 0.52.0",
 ]
 
@@ -2782,7 +2794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
 dependencies = [
  "phf_shared 0.10.0",
- "rand",
+ "rand 0.8.5",
 ]
 
 [[package]]
@@ -2792,7 +2804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
 dependencies = [
  "phf_shared 0.11.3",
- "rand",
+ "rand 0.8.5",
 ]
 
 [[package]]
@@ -2860,7 +2872,7 @@ version = "0.2.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
 dependencies = [
- "zerocopy",
+ "zerocopy 0.7.35",
 ]
 
 [[package]]
@@ -2978,8 +2990,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
- "rand_chacha",
- "rand_core",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.0",
+ "zerocopy 0.8.14",
 ]
 
 [[package]]
@@ -2989,7 +3012,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.0",
 ]
 
 [[package]]
@@ -2998,7 +3031,17 @@ version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
+dependencies = [
+ "getrandom 0.3.1",
+ "zerocopy 0.8.14",
 ]
 
 [[package]]
@@ -3007,7 +3050,7 @@ version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
 dependencies = [
- "rand_core",
+ "rand_core 0.6.4",
 ]
 
 [[package]]
@@ -3045,7 +3088,7 @@ version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
  "libredox",
  "thiserror 1.0.69",
 ]
@@ -3283,7 +3326,7 @@ name = "rustc_abi"
 version = "0.0.0"
 dependencies = [
  "bitflags",
- "rand",
+ "rand 0.8.5",
  "rand_xoshiro",
  "rustc_data_structures",
  "rustc_feature",
@@ -3897,7 +3940,7 @@ dependencies = [
 name = "rustc_incremental"
 version = "0.0.0"
 dependencies = [
- "rand",
+ "rand 0.8.5",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_errors",
@@ -4234,6 +4277,7 @@ name = "rustc_monomorphize"
 version = "0.0.0"
 dependencies = [
  "rustc_abi",
+ "rustc_ast",
  "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
@@ -4243,6 +4287,7 @@ dependencies = [
  "rustc_middle",
  "rustc_session",
  "rustc_span",
+ "rustc_symbol_mangling",
  "rustc_target",
  "serde",
  "serde_json",
@@ -5216,7 +5261,7 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
 dependencies = [
  "cfg-if",
  "fastrand",
- "getrandom",
+ "getrandom 0.2.15",
  "once_cell",
  "rustix",
  "windows-sys 0.59.0",
@@ -5279,8 +5324,8 @@ version = "0.1.0"
 dependencies = [
  "indicatif",
  "num",
- "rand",
- "rand_chacha",
+ "rand 0.8.5",
+ "rand_chacha 0.3.1",
  "rayon",
 ]
 
@@ -5600,7 +5645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
 dependencies = [
  "cfg-if",
- "rand",
+ "rand 0.8.5",
  "static_assertions",
 ]
 
@@ -5661,6 +5706,32 @@ dependencies = [
 ]
 
 [[package]]
+name = "ui_test"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7484683d60d50ca1d1b6433c3dbf6c5ad71d20387acdcfb16fe79573f3fba576"
+dependencies = [
+ "annotate-snippets 0.11.5",
+ "anyhow",
+ "bstr",
+ "cargo-platform",
+ "cargo_metadata 0.18.1",
+ "color-eyre",
+ "colored",
+ "comma",
+ "crossbeam-channel",
+ "indicatif",
+ "levenshtein",
+ "prettydiff",
+ "regex",
+ "rustc_version",
+ "rustfix",
+ "serde",
+ "serde_json",
+ "spanned",
+]
+
+[[package]]
 name = "unic-langid"
 version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5841,7 +5912,7 @@ version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
 ]
 
 [[package]]
@@ -5879,6 +5950,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
+name = "wasi"
+version = "0.13.3+wasi-0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
 name = "wasi-preview1-component-adapter-provider"
 version = "29.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6474,6 +6554,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ab703352da6a72f35c39a533526393725640575bb211f61987a2748323ad956"
 
 [[package]]
+name = "wit-bindgen-rt"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
 name = "wit-component"
 version = "0.223.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6582,7 +6671,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
 dependencies = [
  "byteorder",
- "zerocopy-derive",
+ "zerocopy-derive 0.7.35",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468"
+dependencies = [
+ "zerocopy-derive 0.8.14",
 ]
 
 [[package]]
@@ -6597,6 +6695,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "zerocopy-derive"
+version = "0.8.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.96",
+]
+
+[[package]]
 name = "zerofrom"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/RELEASES.md b/RELEASES.md
index 2da6ed3f100..1dd3fbea613 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,8 +1,22 @@
+Version 1.84.1 (2025-01-30)
+==========================
+
+<a id="1.84.1"></a>
+
+- [Fix ICE 132920 in duplicate-crate diagnostics.](https://github.com/rust-lang/rust/pull/133304/)
+- [Fix errors for overlapping impls in incremental rebuilds.](https://github.com/rust-lang/rust/pull/133828/)
+- [Fix slow compilation related to the next-generation trait solver.](https://github.com/rust-lang/rust/pull/135618/)
+- [Fix debuginfo when LLVM's location discriminator value limit is exceeded.](https://github.com/rust-lang/rust/pull/135643/)
+- Fixes for building Rust from source:
+  - [Only try to distribute `llvm-objcopy` if llvm tools are enabled.](https://github.com/rust-lang/rust/pull/134240/)
+  - [Add Profile Override for Non-Git Sources.](https://github.com/rust-lang/rust/pull/135433/)
+  - [Resolve symlinks of LLVM tool binaries before copying them.](https://github.com/rust-lang/rust/pull/135585/)
+  - [Make it possible to use ci-rustc on tarball sources.](https://github.com/rust-lang/rust/pull/135722/)
+
 Version 1.84.0 (2025-01-09)
 ==========================
 
-<a id="
-Language"></a>
+<a id="1.84.0-Language"></a>
 
 Language
 --------
diff --git a/REUSE.toml b/REUSE.toml
index 6b16d97ed80..9e873e94eff 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -92,7 +92,7 @@ SPDX-FileCopyrightText = "2015 Anders Kaseorg <andersk@mit.edu>"
 SPDX-License-Identifier = "MIT"
 
 [[annotations]]
-path = "src/librustdoc/html/static/fonts/FiraSans**"
+path = "src/librustdoc/html/static/fonts/Fira**"
 precedence = "override"
 SPDX-FileCopyrightText = ["2014, Mozilla Foundation", "2014, Telefonica S.A."]
 SPDX-License-Identifier = "OFL-1.1"
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index ad942e9b494..b6f331d316c 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1657,7 +1657,7 @@ impl GenBlockKind {
 }
 
 /// Whether we're unwrapping or wrapping an unsafe binder
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum UnsafeBinderCastKind {
     // e.g. `&i32` -> `unsafe<'a> &'a i32`
diff --git a/compiler/rustc_ast/src/expand/autodiff_attrs.rs b/compiler/rustc_ast/src/expand/autodiff_attrs.rs
index 7ef8bc17973..ecc522ec39d 100644
--- a/compiler/rustc_ast/src/expand/autodiff_attrs.rs
+++ b/compiler/rustc_ast/src/expand/autodiff_attrs.rs
@@ -79,6 +79,7 @@ pub struct AutoDiffItem {
     pub target: String,
     pub attrs: AutoDiffAttrs,
 }
+
 #[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct AutoDiffAttrs {
     /// Conceptually either forward or reverse mode AD, as described in various autodiff papers and
@@ -231,7 +232,7 @@ impl AutoDiffAttrs {
         self.ret_activity == DiffActivity::ActiveOnly
     }
 
-    pub fn error() -> Self {
+    pub const fn error() -> Self {
         AutoDiffAttrs {
             mode: DiffMode::Error,
             ret_activity: DiffActivity::None,
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 3b7367d1ee2..100f664a89f 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -527,13 +527,13 @@ impl TokenKind {
 
     /// Returns tokens that are likely to be typed accidentally instead of the current token.
     /// Enables better error recovery when the wrong token is found.
-    pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> {
-        match *self {
-            Comma => Some(vec![Dot, Lt, Semi]),
-            Semi => Some(vec![Colon, Comma]),
-            Colon => Some(vec![Semi]),
-            FatArrow => Some(vec![Eq, RArrow, Ge, Gt]),
-            _ => None,
+    pub fn similar_tokens(&self) -> &[TokenKind] {
+        match self {
+            Comma => &[Dot, Lt, Semi],
+            Semi => &[Colon, Comma],
+            Colon => &[Semi],
+            FatArrow => &[Eq, RArrow, Ge, Gt],
+            _ => &[],
         }
     }
 
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index b932915dc29..1267281f73e 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1391,7 +1391,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         None,
                     );
                     // Destructure like a unit struct.
-                    let unit_struct_pat = hir::PatKind::Path(qpath);
+                    let unit_struct_pat = hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
+                        kind: hir::PatExprKind::Path(qpath),
+                        hir_id: self.next_id(),
+                        span: self.lower_span(lhs.span),
+                    }));
                     return self.pat_without_dbm(lhs.span, unit_struct_pat);
                 }
             }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index b9f1a4220b8..893da930855 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -418,10 +418,10 @@ fn compute_hir_hash(
 pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
     let sess = tcx.sess;
     // Queries that borrow `resolver_for_lowering`.
-    tcx.ensure_with_value().output_filenames(());
-    tcx.ensure_with_value().early_lint_checks(());
-    tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE);
-    tcx.ensure_with_value().get_lang_items(());
+    tcx.ensure_done().output_filenames(());
+    tcx.ensure_done().early_lint_checks(());
+    tcx.ensure_done().debugger_visualizers(LOCAL_CRATE);
+    tcx.ensure_done().get_lang_items(());
     let (mut resolver, krate) = tcx.resolver_for_lowering().steal();
 
     let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 3c78ed0497d..cde8ddbfe03 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -69,7 +69,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                             None,
                         );
-                        break hir::PatKind::Path(qpath);
+                        let kind = hir::PatExprKind::Path(qpath);
+                        let span = self.lower_span(pattern.span);
+                        let expr = hir::PatExpr { hir_id: pat_hir_id, span, kind };
+                        let expr = self.arena.alloc(expr);
+                        return hir::Pat {
+                            hir_id: self.next_id(),
+                            kind: hir::PatKind::Expr(expr),
+                            span,
+                            default_binding_modes: true,
+                        };
                     }
                     PatKind::Struct(qself, path, fields, etc) => {
                         let qpath = self.lower_qpath(
@@ -304,16 +313,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 )
             }
             Some(res) => {
-                let hir_id = self.next_id();
                 let res = self.lower_res(res);
-                hir::PatKind::Path(hir::QPath::Resolved(
-                    None,
-                    self.arena.alloc(hir::Path {
-                        span: self.lower_span(ident.span),
-                        res,
-                        segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
-                    }),
-            ))
+                let span = self.lower_span(ident.span);
+                hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
+                    kind: hir::PatExprKind::Path(hir::QPath::Resolved(
+                        None,
+                        self.arena.alloc(hir::Path {
+                            span,
+                            res,
+                            segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), self.next_id(), res)],
+                        }),
+                    )),
+                    hir_id: self.next_id(),
+                    span,
+                }))
             }
         }
     }
diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs
index dfda04387ec..c2213fc9ed8 100644
--- a/compiler/rustc_attr_data_structures/src/stability.rs
+++ b/compiler/rustc_attr_data_structures/src/stability.rs
@@ -101,16 +101,6 @@ impl PartialConstStability {
     }
 }
 
-#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
-#[derive(HashStable_Generic)]
-pub enum AllowedThroughUnstableModules {
-    /// This does not get a deprecation warning. We still generally would prefer people to use the
-    /// fully stable path, and a warning will likely be emitted in the future.
-    WithoutDeprecation,
-    /// Emit the given deprecation warning.
-    WithDeprecation(Symbol),
-}
-
 /// The available stability levels.
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
 #[derive(HashStable_Generic)]
@@ -147,8 +137,9 @@ pub enum StabilityLevel {
     Stable {
         /// Rust release which stabilized this feature.
         since: StableSince,
-        /// This is `Some` if this item allowed to be referred to on stable via unstable modules.
-        allowed_through_unstable_modules: Option<AllowedThroughUnstableModules>,
+        /// This is `Some` if this item allowed to be referred to on stable via unstable modules;
+        /// the `Symbol` is the deprecation message printed in that case.
+        allowed_through_unstable_modules: Option<Symbol>,
     },
 }
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index bfbe51b27d8..454b8b5de82 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -6,12 +6,12 @@ use rustc_ast::MetaItem;
 use rustc_ast::attr::AttributeExt;
 use rustc_ast_pretty::pprust;
 use rustc_attr_data_structures::{
-    AllowedThroughUnstableModules, ConstStability, DefaultBodyStability, Stability, StabilityLevel,
-    StableSince, UnstableReason, VERSION_PLACEHOLDER,
+    ConstStability, DefaultBodyStability, Stability, StabilityLevel, StableSince, UnstableReason,
+    VERSION_PLACEHOLDER,
 };
 use rustc_errors::ErrorGuaranteed;
 use rustc_session::Session;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol, kw, sym};
 
 use crate::attributes::util::UnsupportedLiteralReason;
 use crate::{parse_version, session_diagnostics};
@@ -29,10 +29,14 @@ pub fn find_stability(
     for attr in attrs {
         match attr.name_or_empty() {
             sym::rustc_allowed_through_unstable_modules => {
-                allowed_through_unstable_modules = Some(match attr.value_str() {
-                    Some(msg) => AllowedThroughUnstableModules::WithDeprecation(msg),
-                    None => AllowedThroughUnstableModules::WithoutDeprecation,
-                })
+                // The value is mandatory, but avoid ICEs in case such code reaches this function.
+                allowed_through_unstable_modules = Some(attr.value_str().unwrap_or_else(|| {
+                    sess.dcx().span_delayed_bug(
+                        item_sp,
+                        "`#[rustc_allowed_through_unstable_modules]` without deprecation message",
+                    );
+                    kw::Empty
+                }))
             }
             sym::unstable => {
                 if stab.is_some() {
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index c00e6dde919..ada20e5c614 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -92,9 +92,6 @@ borrowck_lifetime_constraints_error =
 borrowck_limitations_implies_static =
     due to current limitations in the borrow checker, this implies a `'static` lifetime
 
-borrowck_long_type_consider_verbose = consider using `--verbose` to print the full type name to the console
-borrowck_long_type_full_path = the full type name has been written to '{$path}'
-
 borrowck_move_closure_suggestion =
     consider adding 'move' keyword before the nested closure
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 07dcbba019a..dc4e49972ca 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -289,8 +289,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 None => "value".to_owned(),
             };
             if needs_note {
-                let mut path = None;
-                let ty = self.infcx.tcx.short_ty_string(ty, &mut path);
+                let ty = self.infcx.tcx.short_string(ty, err.long_ty_path());
                 if let Some(local) = place.as_local() {
                     let span = self.body.local_decls[local].source_info.span;
                     err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
@@ -306,11 +305,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         place: &note_msg,
                     });
                 };
-                if let Some(path) = path {
-                    err.subdiagnostic(crate::session_diagnostics::LongTypePath {
-                        path: path.display().to_string(),
-                    });
-                }
             }
 
             if let UseSpans::FnSelfUse {
@@ -3777,7 +3771,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         let tcx = self.infcx.tcx;
         if let Some(Terminator { kind: TerminatorKind::Call { call_source, fn_span, .. }, .. }) =
             &self.body[loan.reserve_location.block].terminator
-            && let Some((method_did, method_args)) = rustc_middle::util::find_self_call(
+            && let Some((method_did, method_args)) = mir::find_self_call(
                 tcx,
                 self.body,
                 loan.assigned_place.local,
@@ -3915,7 +3909,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         ProjectionElem::ConstantIndex { .. }
                         | ProjectionElem::Subslice { .. }
                         | ProjectionElem::Subtype(_)
-                        | ProjectionElem::Index(_) => kind,
+                        | ProjectionElem::Index(_)
+                        | ProjectionElem::UnwrapUnsafeBinder(_) => kind,
                     },
                     place_ty.projection_ty(tcx, elem),
                 )
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 2656e0bb6a4..841cb782bc3 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -248,7 +248,98 @@ impl<'tcx> BorrowExplanation<'tcx> {
                         );
                         err.span_label(body.source_info(drop_loc).span, message);
 
-                        if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
+                        struct FindLetExpr<'hir> {
+                            span: Span,
+                            result: Option<(Span, &'hir hir::Pat<'hir>, &'hir hir::Expr<'hir>)>,
+                            tcx: TyCtxt<'hir>,
+                        }
+
+                        impl<'hir> rustc_hir::intravisit::Visitor<'hir> for FindLetExpr<'hir> {
+                            type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
+                            fn nested_visit_map(&mut self) -> Self::Map {
+                                self.tcx.hir()
+                            }
+                            fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
+                                if let hir::ExprKind::If(cond, _conseq, _alt)
+                                | hir::ExprKind::Loop(
+                                    hir::Block {
+                                        expr:
+                                            Some(&hir::Expr {
+                                                kind: hir::ExprKind::If(cond, _conseq, _alt),
+                                                ..
+                                            }),
+                                        ..
+                                    },
+                                    _,
+                                    hir::LoopSource::While,
+                                    _,
+                                ) = expr.kind
+                                    && let hir::ExprKind::Let(hir::LetExpr {
+                                        init: let_expr_init,
+                                        span: let_expr_span,
+                                        pat: let_expr_pat,
+                                        ..
+                                    }) = cond.kind
+                                    && let_expr_init.span.contains(self.span)
+                                {
+                                    self.result =
+                                        Some((*let_expr_span, let_expr_pat, let_expr_init))
+                                } else {
+                                    hir::intravisit::walk_expr(self, expr);
+                                }
+                            }
+                        }
+
+                        if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info()
+                            && let hir::Node::Expr(expr) = tcx.hir_node(if_then)
+                            && let hir::ExprKind::If(cond, conseq, alt) = expr.kind
+                            && let hir::ExprKind::Let(&hir::LetExpr {
+                                span: _,
+                                pat,
+                                init,
+                                // FIXME(#101728): enable rewrite when type ascription is
+                                // stabilized again.
+                                ty: None,
+                                recovered: _,
+                            }) = cond.kind
+                            && pat.span.can_be_used_for_suggestions()
+                            && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
+                        {
+                            suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
+                        } else if let Some((old, new)) = multiple_borrow_span
+                            && let def_id = body.source.def_id()
+                            && let Some(node) = tcx.hir().get_if_local(def_id)
+                            && let Some(body_id) = node.body_id()
+                            && let hir_body = tcx.hir().body(body_id)
+                            && let mut expr_finder = (FindLetExpr { span: old, result: None, tcx })
+                            && let Some((let_expr_span, let_expr_pat, let_expr_init)) = {
+                                expr_finder.visit_expr(hir_body.value);
+                                expr_finder.result
+                            }
+                            && !let_expr_span.contains(new)
+                        {
+                            // #133941: The `old` expression is at the conditional part of an
+                            // if/while let expression. Adding a semicolon won't work.
+                            // Instead, try suggesting the `matches!` macro or a temporary.
+                            if let_expr_pat
+                                .walk_short(|pat| !matches!(pat.kind, hir::PatKind::Binding(..)))
+                            {
+                                if let Ok(pat_snippet) =
+                                    tcx.sess.source_map().span_to_snippet(let_expr_pat.span)
+                                    && let Ok(init_snippet) =
+                                        tcx.sess.source_map().span_to_snippet(let_expr_init.span)
+                                {
+                                    err.span_suggestion_verbose(
+                                        let_expr_span,
+                                        "consider using the `matches!` macro",
+                                        format!("matches!({init_snippet}, {pat_snippet})"),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                } else {
+                                    err.note("consider using the `matches!` macro");
+                                }
+                            }
+                        } else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
                             if info.tail_result_is_ignored {
                                 // #85581: If the first mutable borrow's scope contains
                                 // the second borrow, this suggestion isn't helpful.
@@ -281,23 +372,6 @@ impl<'tcx> BorrowExplanation<'tcx> {
                                     Applicability::MaybeIncorrect,
                                 );
                             };
-                        } else if let &LocalInfo::IfThenRescopeTemp { if_then } =
-                            local_decl.local_info()
-                            && let hir::Node::Expr(expr) = tcx.hir_node(if_then)
-                            && let hir::ExprKind::If(cond, conseq, alt) = expr.kind
-                            && let hir::ExprKind::Let(&hir::LetExpr {
-                                span: _,
-                                pat,
-                                init,
-                                // FIXME(#101728): enable rewrite when type ascription is
-                                // stabilized again.
-                                ty: None,
-                                recovered: _,
-                            }) = cond.kind
-                            && pat.span.can_be_used_for_suggestions()
-                            && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
-                        {
-                            suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
                         }
                     }
                 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index bd6f77156ca..01ed0464c8a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -4,7 +4,7 @@ use std::collections::BTreeMap;
 
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan};
+use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::{self as hir, CoroutineKind, LangItem};
 use rustc_index::IndexSlice;
@@ -17,7 +17,7 @@ use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
     AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
     LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement,
-    StatementKind, Terminator, TerminatorKind,
+    StatementKind, Terminator, TerminatorKind, find_self_call,
 };
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -29,7 +29,7 @@ use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{
-    FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
+    FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
 };
 use tracing::debug;
 
@@ -370,6 +370,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 ProjectionElem::Downcast(..) => (),
                 ProjectionElem::OpaqueCast(..) => (),
                 ProjectionElem::Subtype(..) => (),
+                ProjectionElem::UnwrapUnsafeBinder(_) => (),
                 ProjectionElem::Field(field, _ty) => {
                     // FIXME(project-rfc_2229#36): print capture precisely here.
                     if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -450,9 +451,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
                 }
                 ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
-                ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
-                    PlaceTy::from_ty(*ty)
-                }
+                ProjectionElem::Subtype(ty)
+                | ProjectionElem::OpaqueCast(ty)
+                | ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
                 ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
             },
         };
@@ -1016,12 +1017,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             kind: TerminatorKind::Call { fn_span, call_source, .. }, ..
         }) = &self.body[location.block].terminator
         {
-            let Some((method_did, method_args)) = rustc_middle::util::find_self_call(
-                self.infcx.tcx,
-                self.body,
-                target_temp,
-                location.block,
-            ) else {
+            let Some((method_did, method_args)) =
+                find_self_call(self.infcx.tcx, self.body, target_temp, location.block)
+            else {
                 return normal_ret;
             };
 
@@ -1436,17 +1434,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                                             error.obligation.predicate,
                                         )
                                     }
-                                    [errors @ .., last] => {
+                                    _ => {
                                         format!(
                                             "you could `clone` the value and consume it, if the \
-                                             following trait bounds could be satisfied: \
-                                             {} and `{}`",
-                                            errors
-                                                .iter()
-                                                .map(|e| format!("`{}`", e.obligation.predicate))
-                                                .collect::<Vec<_>>()
-                                                .join(", "),
-                                            last.obligation.predicate,
+                                             following trait bounds could be satisfied: {}",
+                                            listify(&errors, |e: &FulfillmentError<'tcx>| format!(
+                                                "`{}`",
+                                                e.obligation.predicate
+                                            ))
+                                            .unwrap(),
                                         )
                                     }
                                 };
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 14a900f38e9..58c5c2fd774 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -596,19 +596,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         self.suggest_cloning(err, place_ty, expr, None);
                     }
 
-                    let mut path = None;
-                    let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
+                    let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path());
                     err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
                         is_partial_move: false,
                         ty,
                         place: &place_desc,
                         span,
                     });
-                    if let Some(path) = path {
-                        err.subdiagnostic(crate::session_diagnostics::LongTypePath {
-                            path: path.display().to_string(),
-                        });
-                    }
                 } else {
                     binds_to.sort();
                     binds_to.dedup();
@@ -635,19 +629,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     self.suggest_cloning(err, place_ty, expr, Some(use_spans));
                 }
 
-                let mut path = None;
-                let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
+                let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path());
                 err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
                     is_partial_move: false,
                     ty,
                     place: &place_desc,
                     span: use_span,
                 });
-                if let Some(path) = path {
-                    err.subdiagnostic(crate::session_diagnostics::LongTypePath {
-                        path: path.display().to_string(),
-                    });
-                }
 
                 use_spans.args_subdiag(err, |args_span| {
                     crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
@@ -845,19 +833,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     self.suggest_cloning(err, bind_to.ty, expr, None);
                 }
 
-                let mut path = None;
-                let ty = self.infcx.tcx.short_ty_string(bind_to.ty, &mut path);
+                let ty = self.infcx.tcx.short_string(bind_to.ty, err.long_ty_path());
                 err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
                     is_partial_move: false,
                     ty,
                     place: place_desc,
                     span: binding_span,
                 });
-                if let Some(path) = path {
-                    err.subdiagnostic(crate::session_diagnostics::LongTypePath {
-                        path: path.display().to_string(),
-                    });
-                }
             }
         }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index a6ca038282d..706dd7135f7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -167,7 +167,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         | ProjectionElem::ConstantIndex { .. }
                         | ProjectionElem::OpaqueCast { .. }
                         | ProjectionElem::Subslice { .. }
-                        | ProjectionElem::Downcast(..),
+                        | ProjectionElem::Downcast(..)
+                        | ProjectionElem::UnwrapUnsafeBinder(_),
                     ],
             } => bug!("Unexpected immutable place."),
         }
@@ -1140,10 +1141,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         let amp_mut_sugg = match *local_decl.local_info() {
             LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
-                let suggestion = suggest_ampmut_self(self.infcx.tcx, decl_span);
-                let additional =
-                    local_trait.map(|span| (span, suggest_ampmut_self(self.infcx.tcx, span)));
-                Some(AmpMutSugg { has_sugg: true, span: decl_span, suggestion, additional })
+                let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
+                let additional = local_trait.map(|span| suggest_ampmut_self(self.infcx.tcx, span));
+                Some(AmpMutSugg { has_sugg: true, span, suggestion, additional })
             }
 
             LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
@@ -1202,10 +1202,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                                     opt_ty_info: None,
                                     ..
                                 })) => {
-                                    let sugg = suggest_ampmut_self(self.infcx.tcx, decl_span);
+                                    let (span, sugg) =
+                                        suggest_ampmut_self(self.infcx.tcx, decl_span);
                                     Some(AmpMutSugg {
                                         has_sugg: true,
-                                        span: decl_span,
+                                        span,
                                         suggestion: sugg,
                                         additional: None,
                                     })
@@ -1461,17 +1462,12 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symb
     }
 }
 
-fn suggest_ampmut_self<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String {
+fn suggest_ampmut_self(tcx: TyCtxt<'_>, span: Span) -> (Span, String) {
     match tcx.sess.source_map().span_to_snippet(span) {
-        Ok(snippet) => {
-            let lt_pos = snippet.find('\'');
-            if let Some(lt_pos) = lt_pos {
-                format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
-            } else {
-                "&mut self".to_string()
-            }
+        Ok(snippet) if snippet.ends_with("self") => {
+            (span.with_hi(span.hi() - BytePos(4)).shrink_to_hi(), "mut ".to_string())
         }
-        _ => "&mut self".to_string(),
+        _ => (span, "&mut self".to_string()),
     }
 }
 
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index decfab502bb..077d8f49df8 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1398,6 +1398,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     self.consume_operand(location, (operand, span), state);
                 }
             }
+
+            Rvalue::WrapUnsafeBinder(op, _) => {
+                self.consume_operand(location, (op, span), state);
+            }
         }
     }
 
@@ -1770,7 +1774,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                 // So it's safe to skip these.
                 ProjectionElem::OpaqueCast(_)
                 | ProjectionElem::Subtype(_)
-                | ProjectionElem::Downcast(_, _) => (),
+                | ProjectionElem::Downcast(_, _)
+                | ProjectionElem::UnwrapUnsafeBinder(_) => (),
             }
 
             place_ty = place_ty.projection_ty(tcx, elem);
@@ -2004,6 +2009,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                 // FIXME: is this true even if P is an adt with a dtor?
                 { }
 
+                ProjectionElem::UnwrapUnsafeBinder(_) => {
+                    check_parent_of_field(self, location, place_base, span, state);
+                }
+
                 // assigning to (*P) requires P to be initialized
                 ProjectionElem::Deref => {
                     self.check_if_full_path_is_moved(
@@ -2384,7 +2393,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     | ProjectionElem::Subslice { .. }
                     | ProjectionElem::Subtype(..)
                     | ProjectionElem::OpaqueCast { .. }
-                    | ProjectionElem::Downcast(..) => {
+                    | ProjectionElem::Downcast(..)
+                    | ProjectionElem::UnwrapUnsafeBinder(_) => {
                         let upvar_field_projection = self.is_upvar_field_projection(place);
                         if let Some(field) = upvar_field_projection {
                             let upvar = &self.upvars[field.index()];
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 679e111caa9..cf3e82426e8 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -250,7 +250,8 @@ fn place_components_conflict<'tcx>(
                 | (ProjectionElem::Subslice { .. }, _, _)
                 | (ProjectionElem::OpaqueCast { .. }, _, _)
                 | (ProjectionElem::Subtype(_), _, _)
-                | (ProjectionElem::Downcast { .. }, _, _) => {
+                | (ProjectionElem::Downcast { .. }, _, _)
+                | (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => {
                     // Recursive case. This can still be disjoint on a
                     // further iteration if this a shallow access and
                     // there's a deref later on, e.g., a borrow
@@ -519,5 +520,9 @@ fn place_projection_conflict<'tcx>(
             pi1_elem,
             pi2_elem
         ),
+
+        (ProjectionElem::UnwrapUnsafeBinder(_), _) => {
+            todo!()
+        }
     }
 }
diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs
index f71e6f3e6f3..6d32ee17f4c 100644
--- a/compiler/rustc_borrowck/src/polonius/dump.rs
+++ b/compiler/rustc_borrowck/src/polonius/dump.rs
@@ -1,17 +1,19 @@
 use std::io;
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_index::IndexVec;
 use rustc_middle::mir::pretty::{
     PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
 };
-use rustc_middle::mir::{Body, ClosureRegionRequirements};
+use rustc_middle::mir::{Body, ClosureRegionRequirements, Location};
 use rustc_middle::ty::{RegionVid, TyCtxt};
+use rustc_mir_dataflow::points::PointIndex;
 use rustc_session::config::MirIncludeSpans;
 
 use crate::borrow_set::BorrowSet;
 use crate::constraints::OutlivesConstraint;
 use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
+use crate::region_infer::values::LivenessValues;
 use crate::type_check::Locations;
 use crate::{BorrowckInferCtxt, RegionInferenceContext};
 
@@ -80,14 +82,27 @@ fn emit_polonius_dump<'tcx>(
         body,
         regioncx,
         borrow_set,
-        localized_outlives_constraints,
+        &localized_outlives_constraints,
         closure_region_requirements,
         out,
     )?;
     writeln!(out, "</code></pre>")?;
     writeln!(out, "</div>")?;
 
-    // Section 2: mermaid visualization of the CFG.
+    // Section 2: mermaid visualization of the polonius constraint graph.
+    writeln!(out, "<div>")?;
+    writeln!(out, "Polonius constraint graph")?;
+    writeln!(out, "<pre class='mermaid'>")?;
+    let edge_count = emit_mermaid_constraint_graph(
+        borrow_set,
+        regioncx.liveness_constraints(),
+        &localized_outlives_constraints,
+        out,
+    )?;
+    writeln!(out, "</pre>")?;
+    writeln!(out, "</div>")?;
+
+    // Section 3: mermaid visualization of the CFG.
     writeln!(out, "<div>")?;
     writeln!(out, "Control-flow graph")?;
     writeln!(out, "<pre class='mermaid'>")?;
@@ -95,7 +110,7 @@ fn emit_polonius_dump<'tcx>(
     writeln!(out, "</pre>")?;
     writeln!(out, "</div>")?;
 
-    // Section 3: mermaid visualization of the NLL region graph.
+    // Section 4: mermaid visualization of the NLL region graph.
     writeln!(out, "<div>")?;
     writeln!(out, "NLL regions")?;
     writeln!(out, "<pre class='mermaid'>")?;
@@ -103,7 +118,7 @@ fn emit_polonius_dump<'tcx>(
     writeln!(out, "</pre>")?;
     writeln!(out, "</div>")?;
 
-    // Section 4: mermaid visualization of the NLL SCC graph.
+    // Section 5: mermaid visualization of the NLL SCC graph.
     writeln!(out, "<div>")?;
     writeln!(out, "NLL SCCs")?;
     writeln!(out, "<pre class='mermaid'>")?;
@@ -117,7 +132,11 @@ fn emit_polonius_dump<'tcx>(
         "<script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>"
     )?;
     writeln!(out, "<script>")?;
-    writeln!(out, "mermaid.initialize({{ startOnLoad: false, maxEdges: 100 }});")?;
+    writeln!(
+        out,
+        "mermaid.initialize({{ startOnLoad: false, maxEdges: {} }});",
+        edge_count.max(100),
+    )?;
     writeln!(out, "mermaid.run({{ querySelector: '.mermaid' }})")?;
     writeln!(out, "</script>")?;
     writeln!(out, "</body>")?;
@@ -132,7 +151,7 @@ fn emit_html_mir<'tcx>(
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
-    localized_outlives_constraints: LocalizedOutlivesConstraintSet,
+    localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
     closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
     out: &mut dyn io::Write,
 ) -> io::Result<()> {
@@ -160,7 +179,7 @@ fn emit_html_mir<'tcx>(
                 regioncx,
                 closure_region_requirements,
                 borrow_set,
-                &localized_outlives_constraints,
+                localized_outlives_constraints,
                 pass_where,
                 out,
             )
@@ -392,3 +411,76 @@ fn emit_mermaid_nll_sccs<'tcx>(
 
     Ok(())
 }
+
+/// Emits a mermaid flowchart of the polonius localized outlives constraints, with subgraphs per
+/// region, and loan introductions.
+fn emit_mermaid_constraint_graph<'tcx>(
+    borrow_set: &BorrowSet<'tcx>,
+    liveness: &LivenessValues,
+    localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
+    out: &mut dyn io::Write,
+) -> io::Result<usize> {
+    let location_name = |location: Location| {
+        // A MIR location looks like `bb5[2]`. As that is not a syntactically valid mermaid node id,
+        // transform it into `BB5_2`.
+        format!("BB{}_{}", location.block.index(), location.statement_index)
+    };
+    let region_name = |region: RegionVid| format!("'{}", region.index());
+    let node_name = |region: RegionVid, point: PointIndex| {
+        let location = liveness.location_from_point(point);
+        format!("{}_{}", region_name(region), location_name(location))
+    };
+
+    // The mermaid chart type: a top-down flowchart, which supports subgraphs.
+    writeln!(out, "flowchart TD")?;
+
+    // The loans subgraph: a node per loan.
+    writeln!(out, "    subgraph \"Loans\"")?;
+    for loan_idx in 0..borrow_set.len() {
+        writeln!(out, "        L{loan_idx}")?;
+    }
+    writeln!(out, "    end\n")?;
+
+    // And an edge from that loan node to where it enters the constraint graph.
+    for (loan_idx, loan) in borrow_set.iter_enumerated() {
+        writeln!(
+            out,
+            "    L{} --> {}_{}",
+            loan_idx.index(),
+            region_name(loan.region),
+            location_name(loan.reserve_location),
+        )?;
+    }
+    writeln!(out, "")?;
+
+    // The regions subgraphs containing the region/point nodes.
+    let mut points_per_region: FxIndexMap<RegionVid, FxIndexSet<PointIndex>> =
+        FxIndexMap::default();
+    for constraint in &localized_outlives_constraints.outlives {
+        points_per_region.entry(constraint.source).or_default().insert(constraint.from);
+        points_per_region.entry(constraint.target).or_default().insert(constraint.to);
+    }
+    for (region, points) in points_per_region {
+        writeln!(out, "    subgraph \"{}\"", region_name(region))?;
+        for point in points {
+            writeln!(out, "        {}", node_name(region, point))?;
+        }
+        writeln!(out, "    end\n")?;
+    }
+
+    // The constraint graph edges.
+    for constraint in &localized_outlives_constraints.outlives {
+        // FIXME: add killed loans and constraint kind as edge labels.
+        writeln!(
+            out,
+            "    {} --> {}",
+            node_name(constraint.source, constraint.from),
+            node_name(constraint.target, constraint.to),
+        )?;
+    }
+
+    // Return the number of edges: this is the biggest graph in the dump and its edge count will be
+    // mermaid's max edge count to support.
+    let edge_count = borrow_set.len() + localized_outlives_constraints.outlives.len();
+    Ok(edge_count)
+}
diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs
index f79bcf5af55..0d1d8642bca 100644
--- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs
@@ -325,6 +325,10 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
                     self.consume_operand(location, operand);
                 }
             }
+
+            Rvalue::WrapUnsafeBinder(op, _) => {
+                self.consume_operand(location, op);
+            }
         }
     }
 
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index fc7e6e58641..83cca38a5c0 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -66,6 +66,10 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
                             self.next = Some(cursor_base);
                             return Some(cursor);
                         }
+                        ProjectionElem::UnwrapUnsafeBinder(_) => {
+                            self.next = Some(cursor_base);
+                            return Some(cursor);
+                        }
                         ProjectionElem::Downcast(..)
                         | ProjectionElem::Subslice { .. }
                         | ProjectionElem::OpaqueCast { .. }
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 7c484327e31..5440d451ec8 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,6 +1,8 @@
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::OpaqueTyOrigin;
 use rustc_hir::def_id::LocalDefId;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
 use rustc_macros::extension;
 use rustc_middle::ty::fold::fold_regions;
@@ -10,6 +12,7 @@ use rustc_middle::ty::{
     TypingMode,
 };
 use rustc_span::Span;
+use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 use tracing::{debug, instrument};
 
@@ -406,10 +409,6 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
     }
 
     fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> {
-        use rustc_hir as hir;
-        use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-        use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
-
         if let Some(&canonical_args) = self.canonical_args.get() {
             return canonical_args;
         }
@@ -417,9 +416,9 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
         let &Self { tcx, def_id, .. } = self;
         let origin = tcx.local_opaque_ty_origin(def_id);
         let parent = match origin {
-            hir::OpaqueTyOrigin::FnReturn { parent, .. }
-            | hir::OpaqueTyOrigin::AsyncFn { parent, .. }
-            | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
+            OpaqueTyOrigin::FnReturn { parent, .. }
+            | OpaqueTyOrigin::AsyncFn { parent, .. }
+            | OpaqueTyOrigin::TyAlias { parent, .. } => parent,
         };
         let param_env = tcx.param_env(parent);
         let args = GenericArgs::identity_for_item(tcx, parent).extend_to(
@@ -439,8 +438,7 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
             tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds");
             Default::default()
         });
-        let implied_bounds = infcx.implied_bounds_tys(param_env, parent, &wf_tys);
-        let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
+        let outlives_env = OutlivesEnvironment::new(&infcx, parent, param_env, wf_tys);
 
         let mut seen = vec![tcx.lifetimes.re_static];
         let canonical_args = fold_regions(tcx, args, |r1, _| {
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 2c37d2bc123..11b30c145c2 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -459,13 +459,6 @@ pub(crate) enum OnClosureNote<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[note(borrowck_long_type_full_path)]
-#[note(borrowck_long_type_consider_verbose)]
-pub(crate) struct LongTypePath {
-    pub(crate) path: String,
-}
-
-#[derive(Subdiagnostic)]
 pub(crate) enum TypeNoCopy<'a> {
     #[label(borrowck_ty_no_impl_copy)]
     Label {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a2ef5588f48..92492bfdb8d 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -302,6 +302,25 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                     )
                     .unwrap();
             }
+            ProjectionElem::UnwrapUnsafeBinder(ty) => {
+                let ty::UnsafeBinder(binder_ty) = *base_ty.ty.kind() else {
+                    unreachable!();
+                };
+                let found_ty = self.typeck.infcx.instantiate_binder_with_fresh_vars(
+                    self.body().source_info(location).span,
+                    BoundRegionConversionTime::HigherRankedType,
+                    binder_ty.into(),
+                );
+                self.typeck
+                    .relate_types(
+                        ty,
+                        context.ambient_variance(),
+                        found_ty,
+                        location.to_locations(),
+                        ConstraintCategory::Boring,
+                    )
+                    .unwrap();
+            }
             ProjectionElem::Subtype(_) => {
                 bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
             }
@@ -2233,6 +2252,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.check_operand(right, location);
             }
 
+            Rvalue::WrapUnsafeBinder(op, ty) => {
+                self.check_operand(op, location);
+                let operand_ty = op.ty(self.body, self.tcx());
+
+                let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
+                    unreachable!();
+                };
+                let expected_ty = self.infcx.instantiate_binder_with_fresh_vars(
+                    self.body().source_info(location).span,
+                    BoundRegionConversionTime::HigherRankedType,
+                    binder_ty.into(),
+                );
+                self.sub_types(
+                    operand_ty,
+                    expected_ty,
+                    location.to_locations(),
+                    ConstraintCategory::Boring,
+                )
+                .unwrap();
+            }
+
             Rvalue::RawPtr(..)
             | Rvalue::ThreadLocalRef(..)
             | Rvalue::Len(..)
@@ -2258,7 +2298,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             | Rvalue::NullaryOp(..)
             | Rvalue::CopyForDeref(..)
             | Rvalue::UnaryOp(..)
-            | Rvalue::Discriminant(..) => None,
+            | Rvalue::Discriminant(..)
+            | Rvalue::WrapUnsafeBinder(..) => None,
 
             Rvalue::Aggregate(aggregate, _) => match **aggregate {
                 AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
@@ -2450,7 +2491,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 | ProjectionElem::OpaqueCast(..)
                 | ProjectionElem::Index(..)
                 | ProjectionElem::ConstantIndex { .. }
-                | ProjectionElem::Subslice { .. } => {
+                | ProjectionElem::Subslice { .. }
+                | ProjectionElem::UnwrapUnsafeBinder(_) => {
                     // other field access
                 }
                 ProjectionElem::Subtype(_) => {
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index eb01ca3941d..8ab21986e68 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -56,7 +56,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) ->
 
     let (ident, vdata, fields) = match substr.fields {
         Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
-        EnumMatching(_, v, fields) => (v.ident, &v.data, fields),
+        EnumMatching(v, fields) => (v.ident, &v.data, fields),
         AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
         EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => {
             cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
deleted file mode 100644
index 6348560496e..00000000000
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ /dev/null
@@ -1,215 +0,0 @@
-//! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more.
-
-use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Expr, MetaItem, Mutability};
-use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_span::{Ident, Span, Symbol, sym};
-use thin_vec::{ThinVec, thin_vec};
-
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::pathvec_std;
-
-pub(crate) fn expand_deriving_rustc_decodable(
-    cx: &ExtCtxt<'_>,
-    span: Span,
-    mitem: &MetaItem,
-    item: &Annotatable,
-    push: &mut dyn FnMut(Annotatable),
-    is_const: bool,
-) {
-    let krate = sym::rustc_serialize;
-    let typaram = sym::__D;
-
-    let trait_def = TraitDef {
-        span,
-        path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
-        skip_path_as_bound: false,
-        needs_copy_as_bound_if_packed: true,
-        additional_bounds: Vec::new(),
-        supports_unions: false,
-        methods: vec![MethodDef {
-            name: sym::decode,
-            generics: Bounds {
-                bounds: vec![(typaram, vec![Path::new_(
-                    vec![krate, sym::Decoder],
-                    vec![],
-                    PathKind::Global,
-                )])],
-            },
-            explicit_self: false,
-            nonself_args: vec![(
-                Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut),
-                sym::d,
-            )],
-            ret_ty: Path(Path::new_(
-                pathvec_std!(result::Result),
-                vec![
-                    Box::new(Self_),
-                    Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
-                ],
-                PathKind::Std,
-            )),
-            attributes: ast::AttrVec::new(),
-            fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
-            combine_substructure: combine_substructure(Box::new(|a, b, c| {
-                decodable_substructure(a, b, c, krate)
-            })),
-        }],
-        associated_types: Vec::new(),
-        is_const,
-    };
-
-    trait_def.expand(cx, mitem, item, push)
-}
-
-fn decodable_substructure(
-    cx: &ExtCtxt<'_>,
-    trait_span: Span,
-    substr: &Substructure<'_>,
-    krate: Symbol,
-) -> BlockOrExpr {
-    let decoder = substr.nonselflike_args[0].clone();
-    let recurse = vec![
-        Ident::new(krate, trait_span),
-        Ident::new(sym::Decodable, trait_span),
-        Ident::new(sym::decode, trait_span),
-    ];
-    let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
-    // throw an underscore in front to suppress unused variable warnings
-    let blkarg = Ident::new(sym::_d, trait_span);
-    let blkdecoder = cx.expr_ident(trait_span, blkarg);
-
-    let expr = match substr.fields {
-        StaticStruct(_, summary) => {
-            let nfields = match summary {
-                Unnamed(fields, _) => fields.len(),
-                Named(fields) => fields.len(),
-            };
-            let fn_read_struct_field_path: Vec<_> =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct_field]);
-
-            let path = cx.path_ident(trait_span, substr.type_ident);
-            let result =
-                decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| {
-                    cx.expr_try(
-                        span,
-                        cx.expr_call_global(span, fn_read_struct_field_path.clone(), thin_vec![
-                            blkdecoder.clone(),
-                            cx.expr_str(span, name),
-                            cx.expr_usize(span, field),
-                            exprdecode.clone(),
-                        ]),
-                    )
-                });
-            let result = cx.expr_ok(trait_span, result);
-            let fn_read_struct_path: Vec<_> =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct]);
-
-            cx.expr_call_global(trait_span, fn_read_struct_path, thin_vec![
-                decoder,
-                cx.expr_str(trait_span, substr.type_ident.name),
-                cx.expr_usize(trait_span, nfields),
-                cx.lambda1(trait_span, result, blkarg),
-            ])
-        }
-        StaticEnum(_, fields) => {
-            let variant = Ident::new(sym::i, trait_span);
-
-            let mut arms = ThinVec::with_capacity(fields.len() + 1);
-            let mut variants = ThinVec::with_capacity(fields.len());
-
-            let fn_read_enum_variant_arg_path: Vec<_> =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant_arg]);
-
-            for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
-                variants.push(cx.expr_str(v_span, ident.name));
-
-                let path = cx.path(trait_span, vec![substr.type_ident, ident]);
-                let decoded =
-                    decode_static_fields(cx, v_span, path, parts, |cx, span, _, field| {
-                        let idx = cx.expr_usize(span, field);
-                        cx.expr_try(
-                            span,
-                            cx.expr_call_global(
-                                span,
-                                fn_read_enum_variant_arg_path.clone(),
-                                thin_vec![blkdecoder.clone(), idx, exprdecode.clone()],
-                            ),
-                        )
-                    });
-
-                arms.push(cx.arm(v_span, cx.pat_lit(v_span, cx.expr_usize(v_span, i)), decoded));
-            }
-
-            arms.push(cx.arm_unreachable(trait_span));
-
-            let result = cx.expr_ok(
-                trait_span,
-                cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms),
-            );
-            let lambda = cx.lambda(trait_span, vec![blkarg, variant], result);
-            let variant_array_ref = cx.expr_array_ref(trait_span, variants);
-            let fn_read_enum_variant_path: Vec<_> =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]);
-            let result = cx.expr_call_global(trait_span, fn_read_enum_variant_path, thin_vec![
-                blkdecoder,
-                variant_array_ref,
-                lambda
-            ]);
-            let fn_read_enum_path: Vec<_> =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]);
-
-            cx.expr_call_global(trait_span, fn_read_enum_path, thin_vec![
-                decoder,
-                cx.expr_str(trait_span, substr.type_ident.name),
-                cx.lambda1(trait_span, result, blkarg),
-            ])
-        }
-        _ => cx.dcx().bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
-    };
-    BlockOrExpr::new_expr(expr)
-}
-
-/// Creates a decoder for a single enum variant/struct:
-/// - `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: &ExtCtxt<'_>,
-    trait_span: Span,
-    outer_pat_path: ast::Path,
-    fields: &StaticFields,
-    mut getarg: F,
-) -> P<Expr>
-where
-    F: FnMut(&ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>,
-{
-    match fields {
-        Unnamed(fields, is_tuple) => {
-            let path_expr = cx.expr_path(outer_pat_path);
-            if matches!(is_tuple, IsTuple::No) {
-                path_expr
-            } else {
-                let fields = fields
-                    .iter()
-                    .enumerate()
-                    .map(|(i, &span)| getarg(cx, span, Symbol::intern(&format!("_field{i}")), i))
-                    .collect();
-
-                cx.expr_call(trait_span, path_expr, fields)
-            }
-        }
-        Named(fields) => {
-            // use the field's span to get nicer error messages.
-            let fields = fields
-                .iter()
-                .enumerate()
-                .map(|(i, &(ident, span, _))| {
-                    let arg = getarg(cx, span, ident.name, i);
-                    cx.field_imm(span, ident, arg)
-                })
-                .collect();
-            cx.expr_struct(trait_span, outer_pat_path, fields)
-        }
-    }
-}
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 3c7bebd0f19..2388b7dd648 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -42,7 +42,7 @@ pub(crate) fn expand_deriving_default(
                     StaticStruct(_, fields) => {
                         default_struct_substructure(cx, trait_span, substr, fields)
                     }
-                    StaticEnum(enum_def, _) => {
+                    StaticEnum(enum_def) => {
                         default_enum_substructure(cx, trait_span, enum_def, item.span())
                     }
                     _ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"),
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
deleted file mode 100644
index 20aacb2caca..00000000000
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ /dev/null
@@ -1,284 +0,0 @@
-//! The compiler code necessary to implement the `#[derive(RustcEncodable)]`
-//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that
-//! type-defining items may be tagged with
-//! `#[derive(RustcEncodable, RustcDecodable)]`.
-//!
-//! For example, a type like:
-//!
-//! ```ignore (old code)
-//! #[derive(RustcEncodable, RustcDecodable)]
-//! struct Node { id: usize }
-//! ```
-//!
-//! would generate two implementations like:
-//!
-//! ```ignore (old code)
-//! # struct Node { id: usize }
-//! impl<S: Encoder<E>, E> Encodable<S, E> for Node {
-//!     fn encode(&self, s: &mut S) -> Result<(), E> {
-//!         s.emit_struct("Node", 1, |this| {
-//!             this.emit_struct_field("id", 0, |this| {
-//!                 Encodable::encode(&self.id, this)
-//!                 /* this.emit_usize(self.id) can also be used */
-//!             })
-//!         })
-//!     }
-//! }
-//!
-//! impl<D: Decoder<E>, E> Decodable<D, E> for Node {
-//!     fn decode(d: &mut D) -> Result<Node, E> {
-//!         d.read_struct("Node", 1, |this| {
-//!             match this.read_struct_field("id", 0, |this| Decodable::decode(this)) {
-//!                 Ok(id) => Ok(Node { id: id }),
-//!                 Err(e) => Err(e),
-//!             }
-//!         })
-//!     }
-//! }
-//! ```
-//!
-//! Other interesting scenarios are when the item has type parameters or
-//! references other non-built-in types. A type definition like:
-//!
-//! ```ignore (old code)
-//! # #[derive(RustcEncodable, RustcDecodable)]
-//! # struct Span;
-//! #[derive(RustcEncodable, RustcDecodable)]
-//! struct Spanned<T> { node: T, span: Span }
-//! ```
-//!
-//! would yield functions like:
-//!
-//! ```ignore (old code)
-//! # #[derive(RustcEncodable, RustcDecodable)]
-//! # struct Span;
-//! # struct Spanned<T> { node: T, span: Span }
-//! impl<
-//!     S: Encoder<E>,
-//!     E,
-//!     T: Encodable<S, E>
-//! > Encodable<S, E> for Spanned<T> {
-//!     fn encode(&self, s: &mut S) -> Result<(), E> {
-//!         s.emit_struct("Spanned", 2, |this| {
-//!             this.emit_struct_field("node", 0, |this| self.node.encode(this))
-//!                 .unwrap();
-//!             this.emit_struct_field("span", 1, |this| self.span.encode(this))
-//!         })
-//!     }
-//! }
-//!
-//! impl<
-//!     D: Decoder<E>,
-//!     E,
-//!     T: Decodable<D, E>
-//! > Decodable<D, E> for Spanned<T> {
-//!     fn decode(d: &mut D) -> Result<Spanned<T>, E> {
-//!         d.read_struct("Spanned", 2, |this| {
-//!             Ok(Spanned {
-//!                 node: this.read_struct_field("node", 0, |this| Decodable::decode(this))
-//!                     .unwrap(),
-//!                 span: this.read_struct_field("span", 1, |this| Decodable::decode(this))
-//!                     .unwrap(),
-//!             })
-//!         })
-//!     }
-//! }
-//! ```
-
-use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability};
-use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_span::{Ident, Span, Symbol, sym};
-use thin_vec::{ThinVec, thin_vec};
-
-use crate::deriving::generic::ty::*;
-use crate::deriving::generic::*;
-use crate::deriving::pathvec_std;
-
-pub(crate) fn expand_deriving_rustc_encodable(
-    cx: &ExtCtxt<'_>,
-    span: Span,
-    mitem: &MetaItem,
-    item: &Annotatable,
-    push: &mut dyn FnMut(Annotatable),
-    is_const: bool,
-) {
-    let krate = sym::rustc_serialize;
-    let typaram = sym::__S;
-
-    let trait_def = TraitDef {
-        span,
-        path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
-        skip_path_as_bound: false,
-        needs_copy_as_bound_if_packed: true,
-        additional_bounds: Vec::new(),
-        supports_unions: false,
-        methods: vec![MethodDef {
-            name: sym::encode,
-            generics: Bounds {
-                bounds: vec![(typaram, vec![Path::new_(
-                    vec![krate, sym::Encoder],
-                    vec![],
-                    PathKind::Global,
-                )])],
-            },
-            explicit_self: true,
-            nonself_args: vec![(
-                Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut),
-                sym::s,
-            )],
-            ret_ty: Path(Path::new_(
-                pathvec_std!(result::Result),
-                vec![
-                    Box::new(Unit),
-                    Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
-                ],
-                PathKind::Std,
-            )),
-            attributes: AttrVec::new(),
-            fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
-            combine_substructure: combine_substructure(Box::new(|a, b, c| {
-                encodable_substructure(a, b, c, krate)
-            })),
-        }],
-        associated_types: Vec::new(),
-        is_const,
-    };
-
-    trait_def.expand(cx, mitem, item, push)
-}
-
-fn encodable_substructure(
-    cx: &ExtCtxt<'_>,
-    trait_span: Span,
-    substr: &Substructure<'_>,
-    krate: Symbol,
-) -> BlockOrExpr {
-    let encoder = substr.nonselflike_args[0].clone();
-    // throw an underscore in front to suppress unused variable warnings
-    let blkarg = Ident::new(sym::_e, trait_span);
-    let blkencoder = cx.expr_ident(trait_span, blkarg);
-    let fn_path = cx.expr_path(cx.path_global(trait_span, vec![
-        Ident::new(krate, trait_span),
-        Ident::new(sym::Encodable, trait_span),
-        Ident::new(sym::encode, trait_span),
-    ]));
-
-    match substr.fields {
-        Struct(_, fields) => {
-            let fn_emit_struct_field_path =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]);
-            let mut stmts = ThinVec::new();
-            for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() {
-                let name = match name {
-                    Some(id) => id.name,
-                    None => Symbol::intern(&format!("_field{i}")),
-                };
-                let self_ref = cx.expr_addr_of(span, self_expr.clone());
-                let enc =
-                    cx.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]);
-                let lambda = cx.lambda1(span, enc, blkarg);
-                let call = cx.expr_call_global(span, fn_emit_struct_field_path.clone(), thin_vec![
-                    blkencoder.clone(),
-                    cx.expr_str(span, name),
-                    cx.expr_usize(span, i),
-                    lambda,
-                ]);
-
-                // last call doesn't need a try!
-                let last = fields.len() - 1;
-                let call = if i != last {
-                    cx.expr_try(span, call)
-                } else {
-                    cx.expr(span, ExprKind::Ret(Some(call)))
-                };
-
-                let stmt = cx.stmt_expr(call);
-                stmts.push(stmt);
-            }
-
-            // unit structs have no fields and need to return Ok()
-            let blk = if stmts.is_empty() {
-                let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new()));
-                cx.lambda1(trait_span, ok, blkarg)
-            } else {
-                cx.lambda_stmts_1(trait_span, stmts, blkarg)
-            };
-
-            let fn_emit_struct_path =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]);
-
-            let expr = cx.expr_call_global(trait_span, fn_emit_struct_path, thin_vec![
-                encoder,
-                cx.expr_str(trait_span, substr.type_ident.name),
-                cx.expr_usize(trait_span, fields.len()),
-                blk,
-            ]);
-            BlockOrExpr::new_expr(expr)
-        }
-
-        EnumMatching(idx, variant, fields) => {
-            // We're not generating an AST that the borrow checker is expecting,
-            // so we need to generate a unique local variable to take the
-            // mutable loan out on, otherwise we get conflicts which don't
-            // actually exist.
-            let me = cx.stmt_let(trait_span, false, blkarg, encoder);
-            let encoder = cx.expr_ident(trait_span, blkarg);
-
-            let fn_emit_enum_variant_arg_path: Vec<_> =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]);
-
-            let mut stmts = ThinVec::new();
-            if !fields.is_empty() {
-                let last = fields.len() - 1;
-                for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() {
-                    let self_ref = cx.expr_addr_of(span, self_expr.clone());
-                    let enc = cx
-                        .expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]);
-                    let lambda = cx.lambda1(span, enc, blkarg);
-
-                    let call = cx.expr_call_global(
-                        span,
-                        fn_emit_enum_variant_arg_path.clone(),
-                        thin_vec![blkencoder.clone(), cx.expr_usize(span, i), lambda],
-                    );
-                    let call = if i != last {
-                        cx.expr_try(span, call)
-                    } else {
-                        cx.expr(span, ExprKind::Ret(Some(call)))
-                    };
-                    stmts.push(cx.stmt_expr(call));
-                }
-            } else {
-                let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new()));
-                let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok)));
-                stmts.push(cx.stmt_expr(ret_ok));
-            }
-
-            let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
-            let name = cx.expr_str(trait_span, variant.ident.name);
-
-            let fn_emit_enum_variant_path: Vec<_> =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]);
-
-            let call = cx.expr_call_global(trait_span, fn_emit_enum_variant_path, thin_vec![
-                blkencoder,
-                name,
-                cx.expr_usize(trait_span, *idx),
-                cx.expr_usize(trait_span, fields.len()),
-                blk,
-            ]);
-
-            let blk = cx.lambda1(trait_span, call, blkarg);
-            let fn_emit_enum_path: Vec<_> =
-                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]);
-            let expr = cx.expr_call_global(trait_span, fn_emit_enum_path, thin_vec![
-                encoder,
-                cx.expr_str(trait_span, substr.type_ident.name),
-                blk
-            ]);
-            BlockOrExpr::new_mixed(thin_vec![me], Some(expr))
-        }
-
-        _ => cx.dcx().bug("expected Struct or EnumMatching in derive(Encodable)"),
-    }
-}
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index f0a5e44e066..755a733286c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -311,7 +311,7 @@ pub(crate) enum SubstructureFields<'a> {
     /// Matching variants of the enum: variant index, ast::Variant,
     /// fields: the field name is only non-`None` in the case of a struct
     /// variant.
-    EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>),
+    EnumMatching(&'a ast::Variant, Vec<FieldInfo>),
 
     /// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as
     /// if they were fields. The second field is the expression to combine the
@@ -322,7 +322,7 @@ pub(crate) enum SubstructureFields<'a> {
     StaticStruct(&'a ast::VariantData, StaticFields),
 
     /// A static method where `Self` is an enum.
-    StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
+    StaticEnum(&'a ast::EnumDef),
 }
 
 /// Combine the values of all the fields together. The last argument is
@@ -1270,7 +1270,7 @@ impl<'a> MethodDef<'a> {
                     trait_,
                     type_ident,
                     nonselflike_args,
-                    &EnumMatching(0, variant, Vec::new()),
+                    &EnumMatching(variant, Vec::new()),
                 );
             }
         }
@@ -1282,9 +1282,8 @@ impl<'a> MethodDef<'a> {
         // where each tuple has length = selflike_args.len()
         let mut match_arms: ThinVec<ast::Arm> = variants
             .iter()
-            .enumerate()
-            .filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty()))
-            .map(|(index, variant)| {
+            .filter(|&v| !(unify_fieldless_variants && v.data.fields().is_empty()))
+            .map(|variant| {
                 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
                 // (see "Final wrinkle" note below for why.)
 
@@ -1316,7 +1315,7 @@ impl<'a> MethodDef<'a> {
                 // expressions for referencing every field of every
                 // Self arg, assuming all are instances of VariantK.
                 // Build up code associated with such a case.
-                let substructure = EnumMatching(index, variant, fields);
+                let substructure = EnumMatching(variant, fields);
                 let arm_expr = self
                     .call_substructure_method(
                         cx,
@@ -1344,7 +1343,7 @@ impl<'a> MethodDef<'a> {
                         trait_,
                         type_ident,
                         nonselflike_args,
-                        &EnumMatching(0, v, Vec::new()),
+                        &EnumMatching(v, Vec::new()),
                     )
                     .into_expr(cx, span),
                 )
@@ -1407,21 +1406,12 @@ impl<'a> MethodDef<'a> {
         type_ident: Ident,
         nonselflike_args: &[P<Expr>],
     ) -> BlockOrExpr {
-        let summary = enum_def
-            .variants
-            .iter()
-            .map(|v| {
-                let sp = v.span.with_ctxt(trait_.span.ctxt());
-                let summary = trait_.summarise_struct(cx, &v.data);
-                (v.ident, sp, summary)
-            })
-            .collect();
         self.call_substructure_method(
             cx,
             trait_,
             type_ident,
             nonselflike_args,
-            &StaticEnum(enum_def, summary),
+            &StaticEnum(enum_def),
         )
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index af6dc62db7a..f34a6ae1d98 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -21,7 +21,6 @@ pub(crate) struct Path {
 #[derive(Clone)]
 pub(crate) enum PathKind {
     Local,
-    Global,
     Std,
 }
 
@@ -57,7 +56,6 @@ impl Path {
         let params = tys.map(GenericArg::Type).collect();
 
         match self.kind {
-            PathKind::Global => cx.path_all(span, true, idents, params),
             PathKind::Local => cx.path_all(span, false, idents, params),
             PathKind::Std => {
                 let def_site = cx.with_def_site_ctxt(DUMMY_SP);
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index ec058b41313..c112589b131 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -23,9 +23,7 @@ pub(crate) mod bounds;
 pub(crate) mod clone;
 pub(crate) mod coerce_pointee;
 pub(crate) mod debug;
-pub(crate) mod decodable;
 pub(crate) mod default;
-pub(crate) mod encodable;
 pub(crate) mod hash;
 
 #[path = "cmp/eq.rs"]
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index a0ab6375a66..90447da6680 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -8,7 +8,9 @@ use rustc_ast::{
     token,
 };
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
+use rustc_errors::{
+    Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize,
+};
 use rustc_expand::base::*;
 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
@@ -101,15 +103,14 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a,
 
             match p.expect(exp!(Comma)) {
                 Err(err) => {
-                    match token::TokenKind::Comma.similar_tokens() {
-                        Some(tks) if tks.contains(&p.token.kind) => {
-                            // If a similar token is found, then it may be a typo. We
-                            // consider it as a comma, and continue parsing.
-                            err.emit();
-                            p.bump();
-                        }
+                    if token::TokenKind::Comma.similar_tokens().contains(&p.token.kind) {
+                        // If a similar token is found, then it may be a typo. We
+                        // consider it as a comma, and continue parsing.
+                        err.emit();
+                        p.bump();
+                    } else {
                         // Otherwise stop the parsing and return the error.
-                        _ => return Err(err),
+                        return Err(err);
                     }
                 }
                 Ok(Recovered::Yes(_)) => (),
@@ -976,15 +977,11 @@ fn report_invalid_references(
         } else {
             MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect())
         };
-        let arg_list = if let &[index] = &indexes[..] {
-            format!("argument {index}")
-        } else {
-            let tail = indexes.pop().unwrap();
-            format!(
-                "arguments {head} and {tail}",
-                head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
-            )
-        };
+        let arg_list = format!(
+            "argument{} {}",
+            pluralize!(indexes.len()),
+            listify(&indexes, |i: &usize| i.to_string()).unwrap_or_default()
+        );
         e = ecx.dcx().struct_span_err(
             span,
             format!("invalid reference to positional {arg_list} ({num_args_desc})"),
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 0918403b855..6987ae95980 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -132,8 +132,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         Ord: ord::expand_deriving_ord,
         PartialEq: partial_eq::expand_deriving_partial_eq,
         PartialOrd: partial_ord::expand_deriving_partial_ord,
-        RustcDecodable: decodable::expand_deriving_rustc_decodable,
-        RustcEncodable: encodable::expand_deriving_rustc_encodable,
         CoercePointee: coerce_pointee::expand_deriving_coerce_pointee,
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 34066eb83fc..7a40d236b92 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -417,6 +417,16 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                             Some(source_info.span),
                         );
                     }
+                    AssertKind::NullPointerDereference => {
+                        let location = fx.get_caller_location(source_info).load_scalar(fx);
+
+                        codegen_panic_inner(
+                            fx,
+                            rustc_hir::LangItem::PanicNullPointerDereference,
+                            &[location],
+                            Some(source_info.span),
+                        )
+                    }
                     _ => {
                         let location = fx.get_caller_location(source_info).load_scalar(fx);
 
@@ -915,6 +925,10 @@ fn codegen_stmt<'tcx>(
                     }
                     crate::discriminant::codegen_set_discriminant(fx, lval, variant_index);
                 }
+                Rvalue::WrapUnsafeBinder(ref operand, _to_ty) => {
+                    let operand = codegen_operand(fx, operand);
+                    lval.write_cvalue_transmute(fx, operand);
+                }
             }
         }
         StatementKind::StorageLive(_)
@@ -983,7 +997,9 @@ pub(crate) fn codegen_place<'tcx>(
                 cplace = cplace.place_deref(fx);
             }
             PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
-            PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)),
+            PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => {
+                cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty));
+            }
             PlaceElem::Field(field, _ty) => {
                 cplace = cplace.place_field(fx, field);
             }
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 3e7b81a96b6..425b2adf32a 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -6,7 +6,7 @@ use cranelift_module::*;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{AllocId, GlobalAlloc, Scalar, read_target_uint};
-use rustc_middle::ty::{Binder, ExistentialTraitRef, ScalarInt};
+use rustc_middle::ty::{ExistentialTraitRef, ScalarInt};
 
 use crate::prelude::*;
 
@@ -167,7 +167,9 @@ pub(crate) fn codegen_const_value<'tcx>(
                             &mut fx.constants_cx,
                             fx.module,
                             ty,
-                            dyn_ty.principal(),
+                            dyn_ty.principal().map(|principal| {
+                                fx.tcx.instantiate_bound_regions_with_erased(principal)
+                            }),
                         );
                         let local_data_id =
                             fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
@@ -243,7 +245,7 @@ pub(crate) fn data_id_for_vtable<'tcx>(
     cx: &mut ConstantCx,
     module: &mut dyn Module,
     ty: Ty<'tcx>,
-    trait_ref: Option<Binder<'tcx, ExistentialTraitRef<'tcx>>>,
+    trait_ref: Option<ExistentialTraitRef<'tcx>>,
 ) -> DataId {
     let alloc_id = tcx.vtable_allocation((ty, trait_ref));
     data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not)
@@ -460,9 +462,15 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 GlobalAlloc::Memory(target_alloc) => {
                     data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability)
                 }
-                GlobalAlloc::VTable(ty, dyn_ty) => {
-                    data_id_for_vtable(tcx, cx, module, ty, dyn_ty.principal())
-                }
+                GlobalAlloc::VTable(ty, dyn_ty) => data_id_for_vtable(
+                    tcx,
+                    cx,
+                    module,
+                    ty,
+                    dyn_ty
+                        .principal()
+                        .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
+                ),
                 GlobalAlloc::Static(def_id) => {
                     if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
                     {
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 27adf6318e2..a52b18573b1 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -692,7 +692,7 @@ pub(crate) fn run_aot(
 
     if tcx.dep_graph.is_fully_enabled() {
         for cgu in cgus {
-            tcx.ensure().codegen_unit(cgu.name());
+            tcx.ensure_ok().codegen_unit(cgu.name());
         }
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 6d71b8e8aba..d682efd19aa 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -129,12 +129,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 return;
             }
 
-            let idx = generic_args[2]
-                .expect_const()
-                .try_to_valtree()
-                .expect("expected monomorphic const in codegen")
-                .0
-                .unwrap_branch();
+            let idx = generic_args[2].expect_const().to_value().valtree.unwrap_branch();
 
             assert_eq!(x.layout(), y.layout());
             let layout = x.layout();
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 2843e5bbdfb..f8bbb214920 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -61,7 +61,12 @@ pub(crate) fn unsized_info<'tcx>(
                 old_info
             }
         }
-        (_, ty::Dynamic(data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()),
+        (_, ty::Dynamic(data, ..)) => crate::vtable::get_vtable(
+            fx,
+            source,
+            data.principal()
+                .map(|principal| fx.tcx.instantiate_bound_regions_with_erased(principal)),
+        ),
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 82b6178be9d..a460023b59c 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -90,7 +90,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
 pub(crate) fn get_vtable<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     ty: Ty<'tcx>,
-    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
 ) -> Value {
     let data_id = data_id_for_vtable(fx.tcx, &mut fx.constants_cx, fx.module, ty, trait_ref);
     let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func);
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index bd5d6ba387c..20a3482aaa2 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -234,7 +234,12 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                     GlobalAlloc::VTable(ty, dyn_ty) => {
                         let alloc = self
                             .tcx
-                            .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
+                            .global_alloc(self.tcx.vtable_allocation((
+                                ty,
+                                dyn_ty.principal().map(|principal| {
+                                    self.tcx.instantiate_bound_regions_with_erased(principal)
+                                }),
+                            )))
                             .unwrap_memory();
                         let init = const_alloc_to_gcc(self, alloc);
                         self.static_addr_of(init, alloc.inner().align, None)
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 30732c74eb3..570ef938dc4 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::layout::{
     FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError,
     LayoutOfHelpers,
 };
-use rustc_middle::ty::{self, Instance, PolyExistentialTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_span::source_map::respan;
 use rustc_span::{DUMMY_SP, Span};
@@ -90,7 +90,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
     pub function_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>,
     /// Cache generated vtables
     pub vtables:
-        RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
+        RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
 
     // TODO(antoyo): improve the SSA API to not require those.
     /// Mapping from function pointer type to indexes of on stack parameters.
@@ -401,7 +401,7 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
 impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     fn vtables(
         &self,
-    ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
+    ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
         &self.vtables
     }
 
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index 4b84b1dbfd3..86d3de225f7 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -7,7 +7,7 @@ use rustc_data_structures::sync::Lrc;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::{self, Body, SourceScope};
-use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
+use rustc_middle::ty::{ExistentialTraitRef, Instance, Ty};
 use rustc_session::config::DebugInfo;
 use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol};
 use rustc_target::abi::Size;
@@ -214,7 +214,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
     fn create_vtable_debuginfo(
         &self,
         _ty: Ty<'tcx>,
-        _trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
+        _trait_ref: Option<ExistentialTraitRef<'tcx>>,
         _vtable: Self::Value,
     ) {
         // TODO(antoyo)
diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs
index bfe73c38435..58a26801b67 100644
--- a/compiler/rustc_codegen_gcc/tests/run/int.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/int.rs
@@ -3,8 +3,6 @@
 // Run-time:
 //   status: 0
 
-#![feature(const_black_box)]
-
 /*
  * Code
  */
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index d2de62b17f0..2d007416263 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1325,7 +1325,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
     fn get_static(&mut self, def_id: DefId) -> &'ll Value {
         // Forward to the `get_static` method of `CodegenCx`
-        self.cx().get_static(def_id)
+        let s = self.cx().get_static(def_id);
+        // Cast to default address space if globals are in a different addrspace
+        self.cx().const_pointercast(s, self.type_ptr())
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 6b17b5f6989..9e8e4e1c567 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -62,8 +62,8 @@ fn generate_enzyme_call<'ll>(
     // add outer_fn name to ad_name to make it unique, in case users apply autodiff to multiple
     // functions. Unwrap will only panic, if LLVM gave us an invalid string.
     let name = llvm::get_value_name(outer_fn);
-    let outer_fn_name = std::ffi::CStr::from_bytes_with_nul(name).unwrap().to_str().unwrap();
-    ad_name.push_str(outer_fn_name.to_string().as_str());
+    let outer_fn_name = std::str::from_utf8(name).unwrap();
+    ad_name.push_str(outer_fn_name);
 
     // Let us assume the user wrote the following function square:
     //
@@ -255,14 +255,14 @@ fn generate_enzyme_call<'ll>(
             // have no debug info to copy, which would then be ok.
             trace!("no dbg info");
         }
+
         // Now that we copied the metadata, get rid of dummy code.
-        llvm::LLVMRustEraseInstBefore(entry, last_inst);
-        llvm::LLVMRustEraseInstFromParent(last_inst);
+        llvm::LLVMRustEraseInstUntilInclusive(entry, last_inst);
 
-        if cx.val_ty(outer_fn) != cx.type_void() {
-            builder.ret(call);
-        } else {
+        if cx.val_ty(call) == cx.type_void() {
             builder.ret_void();
+        } else {
+            builder.ret(call);
         }
 
         // Let's crash in case that we messed something up above and generated invalid IR.
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index b4e9b9f44f4..8c94a46ebf3 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -225,6 +225,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
                 }
                 llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
+                // Cast to default address space if globals are in a different addrspace
+                let g = self.const_pointercast(g, self.type_ptr());
                 (s.to_owned(), g)
             })
             .1;
@@ -289,7 +291,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                             let alloc = alloc.inner();
                             let value = match alloc.mutability {
                                 Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
-                                _ => self.static_addr_of(init, alloc.align, None),
+                                _ => self.static_addr_of_impl(init, alloc.align, None),
                             };
                             if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty()
                             {
@@ -312,10 +314,15 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     GlobalAlloc::VTable(ty, dyn_ty) => {
                         let alloc = self
                             .tcx
-                            .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal())))
+                            .global_alloc(self.tcx.vtable_allocation((
+                                ty,
+                                dyn_ty.principal().map(|principal| {
+                                    self.tcx.instantiate_bound_regions_with_erased(principal)
+                                }),
+                            )))
                             .unwrap_memory();
                         let init = const_alloc_to_llvm(self, alloc, /*static*/ false);
-                        let value = self.static_addr_of(init, alloc.inner().align, None);
+                        let value = self.static_addr_of_impl(init, alloc.inner().align, None);
                         (value, AddressSpace::DATA)
                     }
                     GlobalAlloc::Static(def_id) => {
@@ -327,7 +334,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 let llval = unsafe {
                     llvm::LLVMConstInBoundsGEP2(
                         self.type_i8(),
-                        self.const_bitcast(base_addr, self.type_ptr_ext(base_addr_space)),
+                        // Cast to the required address space if necessary
+                        self.const_pointercast(base_addr, self.type_ptr_ext(base_addr_space)),
                         &self.const_usize(offset.bytes()),
                         1,
                     )
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index c7114480d8b..c6855dd42e5 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -210,6 +210,14 @@ impl<'ll> CodegenCx<'ll, '_> {
         unsafe { llvm::LLVMConstBitCast(val, ty) }
     }
 
+    pub(crate) fn const_pointercast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
+        unsafe { llvm::LLVMConstPointerCast(val, ty) }
+    }
+
+    /// Create a global variable.
+    ///
+    /// The returned global variable is a pointer in the default address space for globals.
+    /// Fails if a symbol with the given name already exists.
     pub(crate) fn static_addr_of_mut(
         &self,
         cv: &'ll Value,
@@ -233,6 +241,34 @@ impl<'ll> CodegenCx<'ll, '_> {
         gv
     }
 
+    /// Create a global constant.
+    ///
+    /// The returned global variable is a pointer in the default address space for globals.
+    pub(crate) fn static_addr_of_impl(
+        &self,
+        cv: &'ll Value,
+        align: Align,
+        kind: Option<&str>,
+    ) -> &'ll Value {
+        if let Some(&gv) = self.const_globals.borrow().get(&cv) {
+            unsafe {
+                // Upgrade the alignment in cases where the same constant is used with different
+                // alignment requirements
+                let llalign = align.bytes() as u32;
+                if llalign > llvm::LLVMGetAlignment(gv) {
+                    llvm::LLVMSetAlignment(gv, llalign);
+                }
+            }
+            return gv;
+        }
+        let gv = self.static_addr_of_mut(cv, align, kind);
+        unsafe {
+            llvm::LLVMSetGlobalConstant(gv, True);
+        }
+        self.const_globals.borrow_mut().insert(cv, gv);
+        gv
+    }
+
     #[instrument(level = "debug", skip(self))]
     pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value {
         let instance = Instance::mono(self.tcx, def_id);
@@ -384,8 +420,14 @@ impl<'ll> CodegenCx<'ll, '_> {
             let g = if val_llty == llty {
                 g
             } else {
-                // If we created the global with the wrong type,
-                // correct the type.
+                // codegen_static_initializer creates the global value just from the
+                // `Allocation` data by generating one big struct value that is just
+                // all the bytes and pointers after each other. This will almost never
+                // match the type that the static was declared with. Unfortunately
+                // we can't just LLVMConstBitCast our way out of it because that has very
+                // specific rules on what can be cast. So instead of adding a new way to
+                // generate static initializers that match the static's type, we picked
+                // the easier option and retroactively change the type of the static item itself.
                 let name = llvm::get_value_name(g).to_vec();
                 llvm::set_value_name(g, b"");
 
@@ -505,24 +547,15 @@ impl<'ll> CodegenCx<'ll, '_> {
 }
 
 impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> {
+    /// Get a pointer to a global variable.
+    ///
+    /// The pointer will always be in the default address space. If global variables default to a
+    /// different address space, an addrspacecast is inserted.
     fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value {
-        if let Some(&gv) = self.const_globals.borrow().get(&cv) {
-            unsafe {
-                // Upgrade the alignment in cases where the same constant is used with different
-                // alignment requirements
-                let llalign = align.bytes() as u32;
-                if llalign > llvm::LLVMGetAlignment(gv) {
-                    llvm::LLVMSetAlignment(gv, llalign);
-                }
-            }
-            return gv;
-        }
-        let gv = self.static_addr_of_mut(cv, align, kind);
-        unsafe {
-            llvm::LLVMSetGlobalConstant(gv, True);
-        }
-        self.const_globals.borrow_mut().insert(cv, gv);
-        gv
+        let gv = self.static_addr_of_impl(cv, align, kind);
+        // static_addr_of_impl returns the bare global variable, which might not be in the default
+        // address space. Cast to the default address space if necessary.
+        self.const_pointercast(gv, self.type_ptr())
     }
 
     fn codegen_static(&self, def_id: DefId) {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 79381f35a3c..ba4fd75fb94 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -77,8 +77,7 @@ pub(crate) struct CodegenCx<'ll, 'tcx> {
     /// Cache instances of monomorphic and polymorphic items
     pub instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>,
     /// Cache generated vtables
-    pub vtables:
-        RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>,
+    pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), &'ll Value>>,
     /// Cache of constant strings,
     pub const_str_cache: RefCell<FxHashMap<String, &'ll Value>>,
 
@@ -663,15 +662,14 @@ impl<'ll> SimpleCx<'ll> {
 impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn vtables(
         &self,
-    ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>
-    {
+    ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), &'ll Value>> {
         &self.vtables
     }
 
     fn apply_vcall_visibility_metadata(
         &self,
         ty: Ty<'tcx>,
-        poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
         vtable: &'ll Value,
     ) {
         apply_vcall_visibility_metadata(self, ty, poly_trait_ref, vtable);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index fd22421c7fc..9a2473d6cf2 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -298,7 +298,7 @@ struct UsageSets<'tcx> {
 /// Prepare sets of definitions that are relevant to deciding whether something
 /// is an "unused function" for coverage purposes.
 fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
-    let MonoItemPartitions { all_mono_items, codegen_units } =
+    let MonoItemPartitions { all_mono_items, codegen_units, .. } =
         tcx.collect_and_partition_mono_items(());
 
     // Obtain a MIR body for each function participating in codegen, via an
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 8d782a618fc..3a0c7f007bd 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -13,7 +13,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{
-    self, AdtKind, CoroutineArgsExt, Instance, PolyExistentialTraitRef, Ty, TyCtxt, Visibility,
+    self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility,
 };
 use rustc_session::config::{self, DebugInfo, Lto};
 use rustc_span::{DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, Symbol, hygiene};
@@ -919,8 +919,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
         .unwrap_or_default();
     let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
 
-    let dwarf_version =
-        tcx.sess.opts.unstable_opts.dwarf_version.unwrap_or(tcx.sess.target.default_dwarf_version);
+    let dwarf_version = tcx.sess.dwarf_version();
     let is_dwarf_kind =
         matches!(tcx.sess.target.debuginfo_kind, DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym);
     // Don't emit `.debug_pubnames` and `.debug_pubtypes` on DWARFv4 or lower.
@@ -1400,7 +1399,7 @@ pub(crate) fn build_global_var_di_node<'ll>(
 fn build_vtable_type_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     ty: Ty<'tcx>,
-    poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
 ) -> &'ll DIType {
     let tcx = cx.tcx;
 
@@ -1488,10 +1487,30 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
     .di_node
 }
 
+/// Get the global variable for the vtable.
+///
+/// When using global variables, we may have created an addrspacecast to get a pointer to the
+/// default address space if global variables are created in a different address space.
+/// For modifying the vtable, we need the real global variable. This function accepts either a
+/// global variable (which is simply returned), or an addrspacecast constant expression.
+/// If the given value is an addrspacecast, the cast is removed and the global variable behind
+/// the cast is returned.
+fn find_vtable_behind_cast<'ll>(vtable: &'ll Value) -> &'ll Value {
+    // The vtable is a global variable, which may be behind an addrspacecast.
+    unsafe {
+        if let Some(c) = llvm::LLVMIsAConstantExpr(vtable) {
+            if llvm::LLVMGetConstOpcode(c) == llvm::Opcode::AddrSpaceCast {
+                return llvm::LLVMGetOperand(c, 0).unwrap();
+            }
+        }
+    }
+    vtable
+}
+
 pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     ty: Ty<'tcx>,
-    trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
+    trait_ref: Option<ExistentialTraitRef<'tcx>>,
     vtable: &'ll Value,
 ) {
     // FIXME(flip1995): The virtual function elimination optimization only works with full LTO in
@@ -1508,9 +1527,11 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
 
     let Some(trait_ref) = trait_ref else { return };
 
+    // Unwrap potential addrspacecast
+    let vtable = find_vtable_behind_cast(vtable);
     let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
     let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
-    let trait_def_id = trait_ref_self.def_id();
+    let trait_def_id = trait_ref_self.def_id;
     let trait_vis = cx.tcx.visibility(trait_def_id);
 
     let cgus = cx.sess().codegen_units().as_usize();
@@ -1569,7 +1590,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
 pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     ty: Ty<'tcx>,
-    poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
     vtable: &'ll Value,
 ) {
     if cx.dbg_cx.is_none() {
@@ -1581,6 +1602,9 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
         return;
     }
 
+    // Unwrap potential addrspacecast
+    let vtable = find_vtable_behind_cast(vtable);
+
     // When full debuginfo is enabled, we want to try and prevent vtables from being
     // merged. Otherwise debuggers will have a hard time mapping from dyn pointer
     // to concrete type.
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index a37e719d43f..af1d503ad6a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
 use rustc_middle::bug;
-use rustc_middle::ty::{self, PolyExistentialTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, ExistentialTraitRef, Ty, TyCtxt};
 
 use super::{DefinitionLocation, SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
 use crate::common::{AsCCharPtr, CodegenCx};
@@ -44,7 +44,7 @@ pub(super) enum UniqueTypeId<'tcx> {
     /// The ID for the additional wrapper struct type describing an enum variant in CPP-like mode.
     VariantStructTypeCppLikeWrapper(Ty<'tcx>, VariantIdx, private::HiddenZst),
     /// The ID of the artificial type we create for VTables.
-    VTableTy(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>, private::HiddenZst),
+    VTableTy(Ty<'tcx>, Option<ExistentialTraitRef<'tcx>>, private::HiddenZst),
 }
 
 impl<'tcx> UniqueTypeId<'tcx> {
@@ -88,7 +88,7 @@ impl<'tcx> UniqueTypeId<'tcx> {
     pub(crate) fn for_vtable_ty(
         tcx: TyCtxt<'tcx>,
         self_type: Ty<'tcx>,
-        implemented_trait: Option<PolyExistentialTraitRef<'tcx>>,
+        implemented_trait: Option<ExistentialTraitRef<'tcx>>,
     ) -> Self {
         assert_eq!(
             self_type,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index e6778411365..b1ce52667bd 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -22,6 +22,7 @@ use rustc_session::config::{self, DebugInfo};
 use rustc_span::{
     BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId, Symbol,
 };
+use rustc_target::spec::DebuginfoKind;
 use smallvec::SmallVec;
 use tracing::debug;
 
@@ -93,29 +94,31 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
 
     pub(crate) fn finalize(&self, sess: &Session) {
         unsafe { llvm::LLVMRustDIBuilderFinalize(self.builder) };
-        if !sess.target.is_like_msvc {
-            // Debuginfo generation in LLVM by default uses a higher
-            // version of dwarf than macOS currently understands. We can
-            // instruct LLVM to emit an older version of dwarf, however,
-            // for macOS to understand. For more info see #11352
-            // This can be overridden using --llvm-opts -dwarf-version,N.
-            // Android has the same issue (#22398)
-            let dwarf_version =
-                sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version);
-            llvm::add_module_flag_u32(
-                self.llmod,
-                llvm::ModuleFlagMergeBehavior::Warning,
-                "Dwarf Version",
-                dwarf_version,
-            );
-        } else {
-            // Indicate that we want CodeView debug information on MSVC
-            llvm::add_module_flag_u32(
-                self.llmod,
-                llvm::ModuleFlagMergeBehavior::Warning,
-                "CodeView",
-                1,
-            );
+
+        match sess.target.debuginfo_kind {
+            DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
+                // Debuginfo generation in LLVM by default uses a higher
+                // version of dwarf than macOS currently understands. We can
+                // instruct LLVM to emit an older version of dwarf, however,
+                // for macOS to understand. For more info see #11352
+                // This can be overridden using --llvm-opts -dwarf-version,N.
+                // Android has the same issue (#22398)
+                llvm::add_module_flag_u32(
+                    self.llmod,
+                    llvm::ModuleFlagMergeBehavior::Warning,
+                    "Dwarf Version",
+                    sess.dwarf_version(),
+                );
+            }
+            DebuginfoKind::Pdb => {
+                // Indicate that we want CodeView debug information
+                llvm::add_module_flag_u32(
+                    self.llmod,
+                    llvm::ModuleFlagMergeBehavior::Warning,
+                    "CodeView",
+                    1,
+                );
+            }
         }
 
         // Prevent bitcode readers from deleting the debug info.
@@ -585,7 +588,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn create_vtable_debuginfo(
         &self,
         ty: Ty<'tcx>,
-        trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
         vtable: Self::Value,
     ) {
         metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index eab4a9f30c9..43d6ccfcb4a 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1329,7 +1329,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     }
 
     if name == sym::simd_shuffle_generic {
-        let idx = fn_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch();
+        let idx = fn_args[2].expect_const().to_value().valtree.unwrap_branch();
         let n = idx.len() as u64;
 
         let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 729d6f62e24..92b0ce8ffe1 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -4,16 +4,23 @@ use libc::{c_char, c_uint};
 
 use super::ffi::{BasicBlock, Metadata, Module, Type, Value};
 use crate::llvm::Bool;
+
+#[link(name = "llvm-wrapper", kind = "static")]
 extern "C" {
     // Enzyme
     pub fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
-    pub fn LLVMRustEraseInstBefore(BB: &BasicBlock, I: &Value);
+    pub fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value);
     pub fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
     pub fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
     pub fn LLVMRustEraseInstFromParent(V: &Value);
     pub fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
     pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
+}
 
+extern "C" {
+    // Enzyme
+    pub fn LLVMDumpModule(M: &Module);
+    pub fn LLVMDumpValue(V: &Value);
     pub fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
     pub fn LLVMGetReturnType(T: &Type) -> &Type;
     pub fn LLVMGetParams(Fnc: &Value, parms: *mut &Value);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 009d15a932f..cc7c5231aca 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -661,6 +661,79 @@ pub enum MemoryEffects {
     InaccessibleMemOnly,
 }
 
+/// LLVMOpcode
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[repr(C)]
+pub enum Opcode {
+    Ret = 1,
+    Br = 2,
+    Switch = 3,
+    IndirectBr = 4,
+    Invoke = 5,
+    Unreachable = 7,
+    CallBr = 67,
+    FNeg = 66,
+    Add = 8,
+    FAdd = 9,
+    Sub = 10,
+    FSub = 11,
+    Mul = 12,
+    FMul = 13,
+    UDiv = 14,
+    SDiv = 15,
+    FDiv = 16,
+    URem = 17,
+    SRem = 18,
+    FRem = 19,
+    Shl = 20,
+    LShr = 21,
+    AShr = 22,
+    And = 23,
+    Or = 24,
+    Xor = 25,
+    Alloca = 26,
+    Load = 27,
+    Store = 28,
+    GetElementPtr = 29,
+    Trunc = 30,
+    ZExt = 31,
+    SExt = 32,
+    FPToUI = 33,
+    FPToSI = 34,
+    UIToFP = 35,
+    SIToFP = 36,
+    FPTrunc = 37,
+    FPExt = 38,
+    PtrToInt = 39,
+    IntToPtr = 40,
+    BitCast = 41,
+    AddrSpaceCast = 60,
+    ICmp = 42,
+    FCmp = 43,
+    PHI = 44,
+    Call = 45,
+    Select = 46,
+    UserOp1 = 47,
+    UserOp2 = 48,
+    VAArg = 49,
+    ExtractElement = 50,
+    InsertElement = 51,
+    ShuffleVector = 52,
+    ExtractValue = 53,
+    InsertValue = 54,
+    Freeze = 68,
+    Fence = 55,
+    AtomicCmpXchg = 56,
+    AtomicRMW = 57,
+    Resume = 58,
+    LandingPad = 59,
+    CleanupRet = 61,
+    CatchRet = 62,
+    CatchPad = 63,
+    CleanupPad = 64,
+    CatchSwitch = 65,
+}
+
 unsafe extern "C" {
     type Opaque;
 }
@@ -991,7 +1064,10 @@ unsafe extern "C" {
     pub fn LLVMConstPtrToInt<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
     pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
     pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+    pub fn LLVMConstPointerCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
     pub fn LLVMGetAggregateElement(ConstantVal: &Value, Idx: c_uint) -> Option<&Value>;
+    pub fn LLVMGetConstOpcode(ConstantVal: &Value) -> Opcode;
+    pub fn LLVMIsAConstantExpr(Val: &Value) -> Option<&Value>;
 
     // Operations on global variables, functions, and aliases (globals)
     pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
@@ -1048,6 +1124,7 @@ unsafe extern "C" {
     // Operations on instructions
     pub fn LLVMIsAInstruction(Val: &Value) -> Option<&Value>;
     pub fn LLVMGetFirstBasicBlock(Fn: &Value) -> &BasicBlock;
+    pub fn LLVMGetOperand(Val: &Value, Index: c_uint) -> Option<&Value>;
 
     // Operations on call sites
     pub fn LLVMSetInstructionCallConv(Instr: &Value, CC: c_uint);
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index de37de09f5a..22e262546c3 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -16,6 +16,8 @@ codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$erro
 
 codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
 
+codegen_ssa_autodiff_without_lto = using the autodiff feature requires using fat-lto
+
 codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
 
 codegen_ssa_cgu_not_recorded =
@@ -30,6 +32,8 @@ codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
 
 codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}
 
+codegen_ssa_cpu_required = target requires explicitly specifying a cpu with `-C target-cpu`
+
 codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
 
 codegen_ssa_dlltool_fail_import_library =
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index b40bb4ed5d2..ce2161a07eb 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -7,6 +7,7 @@ use std::sync::mpsc::{Receiver, Sender, channel};
 use std::{fs, io, mem, str, thread};
 
 use rustc_ast::attr;
+use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::jobserver::{self, Acquired};
 use rustc_data_structures::memmap::Mmap;
@@ -40,7 +41,7 @@ use tracing::debug;
 use super::link::{self, ensure_removed};
 use super::lto::{self, SerializedModule};
 use super::symbol_export::symbol_name_for_instance_in_crate;
-use crate::errors::ErrorCreatingRemarkDir;
+use crate::errors::{AutodiffWithoutLto, ErrorCreatingRemarkDir};
 use crate::traits::*;
 use crate::{
     CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
@@ -118,6 +119,7 @@ pub struct ModuleConfig {
     pub merge_functions: bool,
     pub emit_lifetime_markers: bool,
     pub llvm_plugins: Vec<String>,
+    pub autodiff: Vec<config::AutoDiff>,
 }
 
 impl ModuleConfig {
@@ -266,6 +268,7 @@ impl ModuleConfig {
 
             emit_lifetime_markers: sess.emit_lifetime_markers(),
             llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]),
+            autodiff: if_regular!(sess.opts.unstable_opts.autodiff.clone(), vec![]),
         }
     }
 
@@ -389,6 +392,7 @@ impl<B: WriteBackendMethods> CodegenContext<B> {
 
 fn generate_lto_work<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
+    autodiff: Vec<AutoDiffItem>,
     needs_fat_lto: Vec<FatLtoInput<B>>,
     needs_thin_lto: Vec<(String, B::ThinBuffer)>,
     import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>,
@@ -397,11 +401,19 @@ fn generate_lto_work<B: ExtraBackendMethods>(
 
     if !needs_fat_lto.is_empty() {
         assert!(needs_thin_lto.is_empty());
-        let module =
+        let mut module =
             B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise());
+        if cgcx.lto == Lto::Fat && !autodiff.is_empty() {
+            let config = cgcx.config(ModuleKind::Regular);
+            module = unsafe { module.autodiff(cgcx, autodiff, config).unwrap() };
+        }
         // We are adding a single work item, so the cost doesn't matter.
         vec![(WorkItem::LTO(module), 0)]
     } else {
+        if !autodiff.is_empty() {
+            let dcx = cgcx.create_dcx();
+            dcx.handle().emit_fatal(AutodiffWithoutLto {});
+        }
         assert!(needs_fat_lto.is_empty());
         let (lto_modules, copy_jobs) = B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules)
             .unwrap_or_else(|e| e.raise());
@@ -1021,6 +1033,9 @@ pub(crate) enum Message<B: WriteBackendMethods> {
     /// Sent from a backend worker thread.
     WorkItem { result: Result<WorkItemResult<B>, Option<WorkerFatalError>>, worker_id: usize },
 
+    /// A vector containing all the AutoDiff tasks that we have to pass to Enzyme.
+    AddAutoDiffItems(Vec<AutoDiffItem>),
+
     /// The frontend has finished generating something (backend IR or a
     /// post-LTO artifact) for a codegen unit, and it should be passed to the
     /// backend. Sent from the main thread.
@@ -1348,6 +1363,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
 
         // This is where we collect codegen units that have gone all the way
         // through codegen and LLVM.
+        let mut autodiff_items = Vec::new();
         let mut compiled_modules = vec![];
         let mut compiled_allocator_module = None;
         let mut needs_link = Vec::new();
@@ -1459,9 +1475,13 @@ fn start_executing_work<B: ExtraBackendMethods>(
                     let needs_thin_lto = mem::take(&mut needs_thin_lto);
                     let import_only_modules = mem::take(&mut lto_import_only_modules);
 
-                    for (work, cost) in
-                        generate_lto_work(&cgcx, needs_fat_lto, needs_thin_lto, import_only_modules)
-                    {
+                    for (work, cost) in generate_lto_work(
+                        &cgcx,
+                        autodiff_items.clone(),
+                        needs_fat_lto,
+                        needs_thin_lto,
+                        import_only_modules,
+                    ) {
                         let insertion_index = work_items
                             .binary_search_by_key(&cost, |&(_, cost)| cost)
                             .unwrap_or_else(|e| e);
@@ -1596,6 +1616,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
                     main_thread_state = MainThreadState::Idle;
                 }
 
+                Message::AddAutoDiffItems(mut items) => {
+                    autodiff_items.append(&mut items);
+                }
+
                 Message::CodegenComplete => {
                     if codegen_state != Aborted {
                         codegen_state = Completed;
@@ -2070,6 +2094,10 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
         drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::<B>)));
     }
 
+    pub(crate) fn submit_autodiff_items(&self, items: Vec<AutoDiffItem>) {
+        drop(self.coordinator.sender.send(Box::new(Message::<B>::AddAutoDiffItems(items))));
+    }
+
     pub(crate) fn check_for_errors(&self, sess: &Session) {
         self.shared_emitter_main.check(sess, false);
     }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index e438bd70c51..df945920ee8 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -18,14 +18,13 @@ use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, Debugger
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
 use rustc_middle::middle::{exported_symbols, lang_items};
 use rustc_middle::mir::BinOp;
-use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
+use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
 use rustc_span::{DUMMY_SP, Symbol, sym};
-use rustc_trait_selection::infer::at::ToTrace;
 use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 use tracing::{debug, info};
@@ -129,14 +128,9 @@ pub fn validate_trivial_unsize<'tcx>(
                     BoundRegionConversionTime::HigherRankedType,
                     hr_source_principal,
                 );
-                let Ok(()) = ocx.eq_trace(
+                let Ok(()) = ocx.eq(
                     &ObligationCause::dummy(),
                     param_env,
-                    ToTrace::to_trace(
-                        &ObligationCause::dummy(),
-                        hr_target_principal,
-                        hr_source_principal,
-                    ),
                     target_principal,
                     source_principal,
                 ) else {
@@ -211,7 +205,12 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 old_info
             }
         }
-        (_, ty::Dynamic(data, _, _)) => meth::get_vtable(cx, source, data.principal()),
+        (_, ty::Dynamic(data, _, _)) => meth::get_vtable(
+            cx,
+            source,
+            data.principal()
+                .map(|principal| bx.tcx().instantiate_bound_regions_with_erased(principal)),
+        ),
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
     }
 }
@@ -615,11 +614,18 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         return ongoing_codegen;
     }
 
+    if tcx.sess.target.need_explicit_cpu && tcx.sess.opts.cg.target_cpu.is_none() {
+        // The target has no default cpu, but none is set explicitly
+        tcx.dcx().emit_fatal(errors::CpuRequired);
+    }
+
     let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
 
     // Run the monomorphization collector and partition the collected items into
     // codegen units.
-    let codegen_units = tcx.collect_and_partition_mono_items(()).codegen_units;
+    let MonoItemPartitions { codegen_units, autodiff_items, .. } =
+        tcx.collect_and_partition_mono_items(());
+    let autodiff_fncs = autodiff_items.to_vec();
 
     // Force all codegen_unit queries so they are already either red or green
     // when compile_codegen_unit accesses them. We are not able to re-execute
@@ -628,7 +634,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
     // unnecessarily.
     if tcx.dep_graph.is_fully_enabled() {
         for cgu in codegen_units {
-            tcx.ensure().codegen_unit(cgu.name());
+            tcx.ensure_ok().codegen_unit(cgu.name());
         }
     }
 
@@ -690,6 +696,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         );
     }
 
+    if !autodiff_fncs.is_empty() {
+        ongoing_codegen.submit_autodiff_items(autodiff_fncs);
+    }
+
     // For better throughput during parallel processing by LLVM, we used to sort
     // CGUs largest to smallest. This would lead to better thread utilization
     // by, for example, preventing a large CGU from being processed last and
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index a0bc2d4ea48..4166387dad0 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -1,5 +1,10 @@
+use std::str::FromStr;
+
 use rustc_ast::attr::list_contains_name;
-use rustc_ast::{MetaItemInner, attr};
+use rustc_ast::expand::autodiff_attrs::{
+    AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
+};
+use rustc_ast::{MetaItem, MetaItemInner, attr};
 use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::codes::*;
@@ -13,6 +18,7 @@ use rustc_middle::middle::codegen_fn_attrs::{
 };
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::query::Providers;
+use rustc_middle::span_bug;
 use rustc_middle::ty::{self as ty, TyCtxt};
 use rustc_session::parse::feature_err;
 use rustc_session::{Session, lint};
@@ -65,6 +71,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
     }
 
+    // If our rustc version supports autodiff/enzyme, then we call our handler
+    // to check for any `#[rustc_autodiff(...)]` attributes.
+    if cfg!(llvm_enzyme) {
+        let ad = autodiff_attrs(tcx, did.into());
+        codegen_fn_attrs.autodiff_item = ad;
+    }
+
     // When `no_builtins` is applied at the crate level, we should add the
     // `no-builtins` attribute to each function to ensure it takes effect in LTO.
     let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
@@ -856,6 +869,109 @@ impl<'a> MixedExportNameAndNoMangleState<'a> {
     }
 }
 
+/// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)]
+/// macros. There are two forms. The pure one without args to mark primal functions (the functions
+/// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the
+/// placeholder functions. We wrote the rustc_autodiff attributes ourself, so this should never
+/// panic, unless we introduced a bug when parsing the autodiff macro.
+fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
+    let attrs = tcx.get_attrs(id, sym::rustc_autodiff);
+
+    let attrs =
+        attrs.filter(|attr| attr.name_or_empty() == sym::rustc_autodiff).collect::<Vec<_>>();
+
+    // check for exactly one autodiff attribute on placeholder functions.
+    // There should only be one, since we generate a new placeholder per ad macro.
+    // FIXME(ZuseZ4): re-enable this check. Currently we add multiple, which doesn't cause harm but
+    // looks strange e.g. under cargo-expand.
+    let attr = match &attrs[..] {
+        [] => return None,
+        [attr] => attr,
+        // These two attributes are the same and unfortunately duplicated due to a previous bug.
+        [attr, _attr2] => attr,
+        _ => {
+            //FIXME(ZuseZ4): Once we fixed our parser, we should also prohibit the two-attribute
+            //branch above.
+            span_bug!(attrs[1].span, "cg_ssa: rustc_autodiff should only exist once per source");
+        }
+    };
+
+    let list = attr.meta_item_list().unwrap_or_default();
+
+    // empty autodiff attribute macros (i.e. `#[autodiff]`) are used to mark source functions
+    if list.is_empty() {
+        return Some(AutoDiffAttrs::source());
+    }
+
+    let [mode, input_activities @ .., ret_activity] = &list[..] else {
+        span_bug!(attr.span, "rustc_autodiff attribute must contain mode and activities");
+    };
+    let mode = if let MetaItemInner::MetaItem(MetaItem { path: ref p1, .. }) = mode {
+        p1.segments.first().unwrap().ident
+    } else {
+        span_bug!(attr.span, "rustc_autodiff attribute must contain mode");
+    };
+
+    // parse mode
+    let mode = match mode.as_str() {
+        "Forward" => DiffMode::Forward,
+        "Reverse" => DiffMode::Reverse,
+        "ForwardFirst" => DiffMode::ForwardFirst,
+        "ReverseFirst" => DiffMode::ReverseFirst,
+        _ => {
+            span_bug!(mode.span, "rustc_autodiff attribute contains invalid mode");
+        }
+    };
+
+    // First read the ret symbol from the attribute
+    let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: ref p1, .. }) = ret_activity {
+        p1.segments.first().unwrap().ident
+    } else {
+        span_bug!(attr.span, "rustc_autodiff attribute must contain the return activity");
+    };
+
+    // Then parse it into an actual DiffActivity
+    let Ok(ret_activity) = DiffActivity::from_str(ret_symbol.as_str()) else {
+        span_bug!(ret_symbol.span, "invalid return activity");
+    };
+
+    // Now parse all the intermediate (input) activities
+    let mut arg_activities: Vec<DiffActivity> = vec![];
+    for arg in input_activities {
+        let arg_symbol = if let MetaItemInner::MetaItem(MetaItem { path: ref p2, .. }) = arg {
+            match p2.segments.first() {
+                Some(x) => x.ident,
+                None => {
+                    span_bug!(
+                        arg.span(),
+                        "rustc_autodiff attribute must contain the input activity"
+                    );
+                }
+            }
+        } else {
+            span_bug!(arg.span(), "rustc_autodiff attribute must contain the input activity");
+        };
+
+        match DiffActivity::from_str(arg_symbol.as_str()) {
+            Ok(arg_activity) => arg_activities.push(arg_activity),
+            Err(_) => {
+                span_bug!(arg_symbol.span, "invalid input activity");
+            }
+        }
+    }
+
+    for &input in &arg_activities {
+        if !valid_input_activity(mode, input) {
+            span_bug!(attr.span, "Invalid input activity {} for {} mode", input, mode);
+        }
+    }
+    if !valid_ret_activity(mode, ret_activity) {
+        span_bug!(attr.span, "Invalid return activity {} for {} mode", ret_activity, mode);
+    }
+
+    Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities })
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
 }
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 869798d8be1..05175371591 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -507,7 +507,7 @@ pub enum VTableNameKind {
 pub fn compute_debuginfo_vtable_name<'tcx>(
     tcx: TyCtxt<'tcx>,
     t: Ty<'tcx>,
-    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
     kind: VTableNameKind,
 ) -> String {
     let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
@@ -530,8 +530,8 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
     }
 
     if let Some(trait_ref) = trait_ref {
-        let trait_ref = tcx
-            .normalize_erasing_late_bound_regions(ty::TypingEnv::fully_monomorphized(), trait_ref);
+        let trait_ref =
+            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref);
         push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
         visited.clear();
         push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
@@ -673,25 +673,23 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
         ty::ConstKind::Param(param) => {
             write!(output, "{}", param.name)
         }
-        ty::ConstKind::Value(ty, valtree) => {
-            match ty.kind() {
+        ty::ConstKind::Value(cv) => {
+            match cv.ty.kind() {
                 ty::Int(ity) => {
-                    // FIXME: directly extract the bits from a valtree instead of evaluating an
-                    // already evaluated `Const` in order to get the bits.
-                    let bits = ct
+                    let bits = cv
                         .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
                         .expect("expected monomorphic const in codegen");
                     let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
                     write!(output, "{val}")
                 }
                 ty::Uint(_) => {
-                    let val = ct
+                    let val = cv
                         .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
                         .expect("expected monomorphic const in codegen");
                     write!(output, "{val}")
                 }
                 ty::Bool => {
-                    let val = ct.try_to_bool().expect("expected monomorphic const in codegen");
+                    let val = cv.try_to_bool().expect("expected monomorphic const in codegen");
                     write!(output, "{val}")
                 }
                 _ => {
@@ -703,9 +701,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
                     // avoiding collisions and will make the emitted type names shorter.
                     let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
                         let mut hasher = StableHasher::new();
-                        hcx.while_hashing_spans(false, |hcx| {
-                            (ty, valtree).hash_stable(hcx, &mut hasher)
-                        });
+                        hcx.while_hashing_spans(false, |hcx| cv.hash_stable(hcx, &mut hasher));
                         hasher.finish::<Hash64>()
                     });
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 5e684632fb2..3ddbe4aeeec 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -40,6 +40,10 @@ pub(crate) struct CguNotRecorded<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(codegen_ssa_autodiff_without_lto)]
+pub struct AutodiffWithoutLto;
+
+#[derive(Diagnostic)]
 #[diag(codegen_ssa_unknown_reuse_kind)]
 pub(crate) struct UnknownReuseKind {
     #[primary_span]
@@ -524,6 +528,10 @@ pub(crate) struct CheckInstalledVisualStudio;
 pub(crate) struct InsufficientVSCodeProduct;
 
 #[derive(Diagnostic)]
+#[diag(codegen_ssa_cpu_required)]
+pub(crate) struct CpuRequired;
+
+#[derive(Diagnostic)]
 #[diag(codegen_ssa_processing_dymutil_failed)]
 #[note]
 pub(crate) struct ProcessingDymutilFailed {
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index 64cd4c38937..399c592432a 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -1,5 +1,5 @@
 use rustc_middle::bug;
-use rustc_middle::ty::{self, GenericArgKind, Ty};
+use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt};
 use rustc_session::config::Lto;
 use rustc_symbol_mangling::typeid_for_trait_ref;
 use rustc_target::callconv::FnAbi;
@@ -72,12 +72,19 @@ impl<'a, 'tcx> VirtualIndex {
 
 /// This takes a valid `self` receiver type and extracts the principal trait
 /// ref of the type. Return `None` if there is no principal trait.
-fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> {
+fn dyn_trait_in_self<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<ty::ExistentialTraitRef<'tcx>> {
     for arg in ty.peel_refs().walk() {
         if let GenericArgKind::Type(ty) = arg.unpack()
             && let ty::Dynamic(data, _, _) = ty.kind()
         {
-            return data.principal();
+            // FIXME(arbitrary_self_types): This is likely broken for receivers which
+            // have a "non-self" trait objects as a generic argument.
+            return data
+                .principal()
+                .map(|principal| tcx.instantiate_bound_regions_with_erased(principal));
         }
     }
 
@@ -96,7 +103,7 @@ fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> {
 pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
     cx: &Cx,
     ty: Ty<'tcx>,
-    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
 ) -> Cx::Value {
     let tcx = cx.tcx();
 
@@ -131,7 +138,7 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
         && bx.cx().sess().lto() == Lto::Fat
     {
-        if let Some(trait_ref) = dyn_trait_in_self(ty) {
+        if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) {
             let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap();
             let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
             return func;
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index b0a1dedd646..4be363ca9a2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -713,6 +713,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 // and `#[track_caller]` adds an implicit third argument.
                 (LangItem::PanicMisalignedPointerDereference, vec![required, found, location])
             }
+            AssertKind::NullPointerDereference => {
+                // It's `fn panic_null_pointer_dereference()`,
+                // `#[track_caller]` adds an implicit argument.
+                (LangItem::PanicNullPointerDereference, vec![location])
+            }
             _ => {
                 // It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument.
                 (msg.panic_function(), vec![location])
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 7676e1e171a..eafc551501c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -43,7 +43,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Const::Ty(_, c) => match c.kind() {
                 // A constant that came from a const generic but was then used as an argument to
                 // old-style simd_shuffle (passing as argument instead of as a generic param).
-                rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Ok(valtree)),
+                rustc_type_ir::ConstKind::Value(cv) => return Ok(Ok(cv.valtree)),
                 other => span_bug!(constant.span, "{other:#?}"),
             },
             // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index c634f864ffb..73a41676802 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -502,6 +502,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     bug!("encountered OpaqueCast({ty}) in codegen")
                 }
                 mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
+                mir::ProjectionElem::UnwrapUnsafeBinder(ty) => {
+                    cg_base.project_type(bx, self.monomorphize(ty))
+                }
                 mir::ProjectionElem::Index(index) => {
                     let index = &mir::Operand::Copy(mir::Place::from(index));
                     let index = self.codegen_operand(bx, index);
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index d7fc5e8e673..85de3238b3e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -823,6 +823,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
                 OperandRef { val: OperandValue::Immediate(val), layout: box_layout }
             }
+            mir::Rvalue::WrapUnsafeBinder(ref operand, binder_ty) => {
+                let operand = self.codegen_operand(bx, operand);
+                let binder_ty = self.monomorphize(binder_ty);
+                let layout = bx.cx().layout_of(binder_ty);
+                OperandRef { val: operand.val, layout }
+            }
         }
     }
 
@@ -1123,7 +1129,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Rvalue::Discriminant(..) |
             mir::Rvalue::NullaryOp(..) |
             mir::Rvalue::ThreadLocalRef(_) |
-            mir::Rvalue::Use(..) => // (*)
+            mir::Rvalue::Use(..) |
+            mir::Rvalue::WrapUnsafeBinder(..) => // (*)
                 true,
             // Arrays are always aggregates, so it's not worth checking anything here.
             // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)
diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
index fe135e911fb..30d77c206a5 100644
--- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
@@ -2,7 +2,7 @@ use std::ops::Range;
 
 use rustc_abi::Size;
 use rustc_middle::mir;
-use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
+use rustc_middle::ty::{ExistentialTraitRef, Instance, Ty};
 use rustc_span::{SourceFile, Span, Symbol};
 use rustc_target::callconv::FnAbi;
 
@@ -13,7 +13,7 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes {
     fn create_vtable_debuginfo(
         &self,
         ty: Ty<'tcx>,
-        trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
+        trait_ref: Option<ExistentialTraitRef<'tcx>>,
         vtable: Self::Value,
     );
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs
index 5b33fd7ab10..4004947b464 100644
--- a/compiler/rustc_codegen_ssa/src/traits/misc.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs
@@ -10,11 +10,11 @@ use super::BackendTypes;
 pub trait MiscCodegenMethods<'tcx>: BackendTypes {
     fn vtables(
         &self,
-    ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Self::Value>>;
+    ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), Self::Value>>;
     fn apply_vcall_visibility_metadata(
         &self,
         _ty: Ty<'tcx>,
-        _poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        _poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
         _vtable: Self::Value,
     ) {
     }
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index d600d223bff..eecc6690f51 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -280,7 +280,9 @@ const_eval_nullary_intrinsic_fail =
     could not evaluate nullary intrinsic
 
 const_eval_offset_from_different_allocations =
-    `{$name}` called on pointers into different allocations
+    `{$name}` called on two different pointers that are not both derived from the same allocation
+const_eval_offset_from_out_of_bounds =
+    `{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation
 const_eval_offset_from_overflow =
     `{$name}` called when first pointer is too far ahead of second
 const_eval_offset_from_test =
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 16ead1b9785..e8052a3c83a 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -634,7 +634,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place) => {
                 // These are only inserted for slice length, so the place must already be indirect.
                 // This implies we do not have to worry about whether the borrow escapes.
-                assert!(place.is_indirect(), "fake borrows are always indirect");
+                if !place.is_indirect() {
+                    self.tcx.dcx().span_delayed_bug(
+                        self.body.source_info(location).span,
+                        "fake borrows are always indirect",
+                    );
+                }
             }
 
             Rvalue::Cast(
@@ -723,6 +728,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     );
                 }
             }
+
+            Rvalue::WrapUnsafeBinder(..) => {
+                // Unsafe binders are always trivial to create.
+            }
         }
     }
 
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index e244b50a4b5..9c99782d223 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -258,6 +258,8 @@ where
             in_place::<Q, _>(cx, in_local, place.as_ref())
         }
 
+        Rvalue::WrapUnsafeBinder(op, _) => in_operand::<Q, _>(cx, in_local, op),
+
         Rvalue::Aggregate(kind, operands) => {
             // Return early if we know that the struct or enum being constructed is always
             // qualified.
@@ -297,7 +299,8 @@ where
             | ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Downcast(_, _)
-            | ProjectionElem::Index(_) => {}
+            | ProjectionElem::Index(_)
+            | ProjectionElem::UnwrapUnsafeBinder(_) => {}
         }
 
         let base_ty = place_base.ty(cx.body, cx.tcx);
@@ -345,7 +348,7 @@ where
         Const::Ty(_, ct)
             if matches!(
                 ct.kind(),
-                ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_, _)
+                ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
             ) =>
         {
             None
diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs
index 79df63a9e84..8cee282311f 100644
--- a/compiler/rustc_const_eval/src/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs
@@ -202,7 +202,8 @@ where
             | mir::Rvalue::NullaryOp(..)
             | mir::Rvalue::UnaryOp(..)
             | mir::Rvalue::Discriminant(..)
-            | mir::Rvalue::Aggregate(..) => {}
+            | mir::Rvalue::Aggregate(..)
+            | mir::Rvalue::WrapUnsafeBinder(..) => {}
         }
     }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index cfdfbdb7880..82e0a6e6666 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -21,9 +21,10 @@ use super::error::*;
 use crate::errors::{LongRunning, LongRunningWarn};
 use crate::fluent_generated as fluent;
 use crate::interpret::{
-    self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy,
-    InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar, compile_time_machine, interp_ok,
-    throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
+    self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
+    GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar,
+    compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom,
+    throw_unsup, throw_unsup_format,
 };
 
 /// When hitting this many interpreted terminators we emit a deny by default lint
@@ -420,6 +421,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                     Size::from_bytes(size),
                     align,
                     interpret::MemoryKind::Machine(MemoryKind::Heap),
+                    AllocInit::Uninit,
                 )?;
                 ecx.write_pointer(ptr, dest)?;
             }
@@ -506,6 +508,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                     found: eval_to_int(found)?,
                 }
             }
+            NullPointerDereference => NullPointerDereference,
         };
         Err(ConstEvalErrKind::AssertFailure(err)).into()
     }
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 34f795bda75..c0438fb3ff8 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -1,7 +1,7 @@
 // Not in interpret to make sure we do not use private implementation details
 
 use rustc_abi::VariantIdx;
-use rustc_middle::query::{Key, TyCtxtAt};
+use rustc_middle::query::Key;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
@@ -35,16 +35,17 @@ pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeC
 
 #[instrument(skip(tcx), level = "debug")]
 pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
-    tcx: TyCtxtAt<'tcx>,
+    tcx: TyCtxt<'tcx>,
     val: mir::ConstValue<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<mir::DestructuredConstant<'tcx>> {
     let typing_env = ty::TypingEnv::fully_monomorphized();
-    let (ecx, op) = mk_eval_cx_for_const_val(tcx, typing_env, val, ty)?;
+    // FIXME: use a proper span here?
+    let (ecx, op) = mk_eval_cx_for_const_val(tcx.at(rustc_span::DUMMY_SP), typing_env, val, ty)?;
 
     // We go to `usize` as we cannot allocate anything bigger anyway.
     let (field_count, variant, down) = match ty.kind() {
-        ty::Array(_, len) => (len.try_to_target_usize(tcx.tcx)? as usize, None, op),
+        ty::Array(_, len) => (len.try_to_target_usize(tcx)? as usize, None, op),
         ty::Adt(def, _) if def.variants().is_empty() => {
             return None;
         }
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 4ff8aa9a3b4..4d625f76aba 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -272,7 +272,8 @@ pub(crate) fn eval_to_valtree<'tcx>(
 
 /// Converts a `ValTree` to a `ConstValue`, which is needed after mir
 /// construction has finished.
-// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
+// FIXME(valtrees): Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
+// FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately.
 #[instrument(skip(tcx), level = "debug", ret)]
 pub fn valtree_to_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index e6a34193c9d..e2e6e16d8a7 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -5,6 +5,7 @@ use std::borrow::Cow;
 
 use either::{Left, Right};
 use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx};
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
 use rustc_middle::{bug, mir, span_bug};
@@ -693,25 +694,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 trace!("Virtual call dispatches to {fn_inst:#?}");
                 // We can also do the lookup based on `def_id` and `dyn_ty`, and check that that
                 // produces the same result.
-                if cfg!(debug_assertions) {
-                    let tcx = *self.tcx;
-
-                    let trait_def_id = tcx.trait_of_item(def_id).unwrap();
-                    let virtual_trait_ref =
-                        ty::TraitRef::from_method(tcx, trait_def_id, instance.args);
-                    let existential_trait_ref =
-                        ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
-                    let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
-
-                    let concrete_method = Instance::expect_resolve_for_vtable(
-                        tcx,
-                        self.typing_env,
-                        def_id,
-                        instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
-                        self.cur_span(),
-                    );
-                    assert_eq!(fn_inst, concrete_method);
-                }
+                self.assert_virtual_instance_matches_concrete(dyn_ty, def_id, instance, fn_inst);
 
                 // Adjust receiver argument. Layout can be any (thin) ptr.
                 let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty);
@@ -744,6 +727,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
     }
 
+    fn assert_virtual_instance_matches_concrete(
+        &self,
+        dyn_ty: Ty<'tcx>,
+        def_id: DefId,
+        virtual_instance: ty::Instance<'tcx>,
+        concrete_instance: ty::Instance<'tcx>,
+    ) {
+        let tcx = *self.tcx;
+
+        let trait_def_id = tcx.trait_of_item(def_id).unwrap();
+        let virtual_trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, virtual_instance.args);
+        let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
+        let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
+
+        let concrete_method = Instance::expect_resolve_for_vtable(
+            tcx,
+            self.typing_env,
+            def_id,
+            virtual_instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
+            self.cur_span(),
+        );
+        assert_eq!(concrete_instance, concrete_method);
+    }
+
     /// Initiate a tail call to this function -- popping the current stack frame, pushing the new
     /// stack frame and initializing the arguments.
     pub(super) fn init_fn_tail_call(
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index ef3e96784ce..e110c155da0 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -414,36 +414,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
                 // Sanity-check that `supertrait_vtable_slot` in this type's vtable indeed produces
                 // our destination trait.
-                if cfg!(debug_assertions) {
-                    let vptr_entry_idx =
-                        self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
-                    let vtable_entries = self.vtable_entries(data_a.principal(), ty);
-                    if let Some(entry_idx) = vptr_entry_idx {
-                        let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
-                            vtable_entries.get(entry_idx)
-                        else {
-                            span_bug!(
-                                self.cur_span(),
-                                "invalid vtable entry index in {} -> {} upcast",
-                                src_pointee_ty,
-                                dest_pointee_ty
-                            );
-                        };
-                        let erased_trait_ref = upcast_trait_ref
-                            .map_bound(|r| ty::ExistentialTraitRef::erase_self_ty(*self.tcx, r));
-                        assert!(
-                            data_b
-                                .principal()
-                                .is_some_and(|b| self.eq_in_param_env(erased_trait_ref, b))
+                let vptr_entry_idx =
+                    self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
+                let vtable_entries = self.vtable_entries(data_a.principal(), ty);
+                if let Some(entry_idx) = vptr_entry_idx {
+                    let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
+                        vtable_entries.get(entry_idx)
+                    else {
+                        span_bug!(
+                            self.cur_span(),
+                            "invalid vtable entry index in {} -> {} upcast",
+                            src_pointee_ty,
+                            dest_pointee_ty
                         );
-                    } else {
-                        // In this case codegen would keep using the old vtable. We don't want to do
-                        // that as it has the wrong trait. The reason codegen can do this is that
-                        // one vtable is a prefix of the other, so we double-check that.
-                        let vtable_entries_b = self.vtable_entries(data_b.principal(), ty);
-                        assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b);
                     };
-                }
+                    let erased_trait_ref =
+                        ty::ExistentialTraitRef::erase_self_ty(*self.tcx, upcast_trait_ref);
+                    assert!(data_b.principal().is_some_and(|b| self.eq_in_param_env(
+                        erased_trait_ref,
+                        self.tcx.instantiate_bound_regions_with_erased(b)
+                    )));
+                } else {
+                    // In this case codegen would keep using the old vtable. We don't want to do
+                    // that as it has the wrong trait. The reason codegen can do this is that
+                    // one vtable is a prefix of the other, so we double-check that.
+                    let vtable_entries_b = self.vtable_entries(data_b.principal(), ty);
+                    assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b);
+                };
 
                 // Get the destination trait vtable and return that.
                 let new_vptr = self.get_vtable_ptr(ty, data_b)?;
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 0664a882c1d..4ca317e3a1e 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -319,7 +319,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
                 // Check that the memory between them is dereferenceable at all, starting from the
                 // origin pointer: `dist` is `a - b`, so it is based on `b`.
-                self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)?;
+                self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)
+                    .map_err_kind(|_| {
+                        // This could mean they point to different allocations, or they point to the same allocation
+                        // but not the entire range between the pointers is in-bounds.
+                        if let Ok((a_alloc_id, ..)) = self.ptr_try_get_alloc_id(a, 0)
+                            && let Ok((b_alloc_id, ..)) = self.ptr_try_get_alloc_id(b, 0)
+                            && a_alloc_id == b_alloc_id
+                        {
+                            err_ub_custom!(
+                                fluent::const_eval_offset_from_out_of_bounds,
+                                name = intrinsic_name,
+                            )
+                        } else {
+                            err_ub_custom!(
+                                fluent::const_eval_offset_from_different_allocations,
+                                name = intrinsic_name,
+                            )
+                        }
+                    })?;
                 // Then check that this is also dereferenceable from `a`. This ensures that they are
                 // derived from the same allocation.
                 self.check_ptr_access_signed(
@@ -747,7 +765,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     {
         let a: F = self.read_scalar(&args[0])?.to_float()?;
         let b: F = self.read_scalar(&args[1])?.to_float()?;
-        let res = self.adjust_nan(a.min(b), &[a, b]);
+        let res = if a == b {
+            // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
+            // Let the machine decide which one to return.
+            M::equal_float_min_max(self, a, b)
+        } else {
+            self.adjust_nan(a.min(b), &[a, b])
+        };
         self.write_scalar(res, dest)?;
         interp_ok(())
     }
@@ -762,7 +786,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     {
         let a: F = self.read_scalar(&args[0])?.to_float()?;
         let b: F = self.read_scalar(&args[1])?.to_float()?;
-        let res = self.adjust_nan(a.max(b), &[a, b]);
+        let res = if a == b {
+            // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`.
+            // Let the machine decide which one to return.
+            M::equal_float_min_max(self, a, b)
+        } else {
+            self.adjust_nan(a.max(b), &[a, b])
+        };
         self.write_scalar(res, dest)?;
         interp_ok(())
     }
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 36e5a2ff750..8f6b15b8df0 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -278,6 +278,12 @@ pub trait Machine<'tcx>: Sized {
         F2::NAN
     }
 
+    /// Determines the result of `min`/`max` on floats when the arguments are equal.
+    fn equal_float_min_max<F: Float>(_ecx: &InterpCx<'tcx, Self>, a: F, _b: F) -> F {
+        // By default, we pick the left argument.
+        a
+    }
+
     /// Called before a basic block terminator is executed.
     #[inline]
     fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 2772c94d52b..4f4b6785844 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -20,10 +20,10 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use tracing::{debug, instrument, trace};
 
 use super::{
-    AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg,
-    CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
-    PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub,
-    throw_ub_custom, throw_unsup, throw_unsup_format,
+    AllocBytes, AllocId, AllocInit, AllocMap, AllocRange, Allocation, CheckAlignMsg,
+    CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak,
+    Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub,
+    err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
 };
 use crate::fluent_generated as fluent;
 
@@ -230,11 +230,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         size: Size,
         align: Align,
         kind: MemoryKind<M::MemoryKind>,
+        init: AllocInit,
     ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let alloc = if M::PANIC_ON_ALLOC_FAIL {
-            Allocation::uninit(size, align)
+            Allocation::new(size, align, init)
         } else {
-            Allocation::try_uninit(size, align)?
+            Allocation::try_new(size, align, init)?
         };
         self.insert_allocation(alloc, kind)
     }
@@ -270,6 +271,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind))
     }
 
+    /// If this grows the allocation, `init_growth` determines
+    /// whether the additional space will be initialized.
     pub fn reallocate_ptr(
         &mut self,
         ptr: Pointer<Option<M::Provenance>>,
@@ -277,6 +280,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         new_size: Size,
         new_align: Align,
         kind: MemoryKind<M::MemoryKind>,
+        init_growth: AllocInit,
     ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?;
         if offset.bytes() != 0 {
@@ -289,7 +293,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc".
         // This happens so rarely, the perf advantage is outweighed by the maintenance cost.
-        let new_ptr = self.allocate_ptr(new_size, new_align, kind)?;
+        // If requested, we zero-init the entire allocation, to ensure that a growing
+        // allocation has its new bytes properly set. For the part that is copied,
+        // `mem_copy` below will de-initialize things as necessary.
+        let new_ptr = self.allocate_ptr(new_size, new_align, kind, init_growth)?;
         let old_size = match old_size_and_align {
             Some((size, _align)) => size,
             None => self.get_alloc_raw(alloc_id)?.size(),
@@ -830,9 +837,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// [`InterpCx::get_alloc_info`] if all you need to check is whether the kind is
     /// [`AllocKind::Dead`] because it doesn't have to look up the type and layout of statics.
     pub fn is_alloc_live(&self, id: AllocId) -> bool {
-        self.tcx.try_get_global_alloc(id).is_some()
-            || self.memory.alloc_map.contains_key_ref(&id)
+        self.memory.alloc_map.contains_key_ref(&id)
             || self.memory.extra_fn_ptr_map.contains_key(&id)
+            // We check `tcx` last as that has to acquire a lock in `many-seeds` mode.
+            // This also matches the order in `get_alloc_info`.
+            || self.tcx.try_get_global_alloc(id).is_some()
     }
 
     /// Obtain the size and alignment of an allocation, even if that allocation has
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index c97922ac132..f5d3de7b1b2 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -12,9 +12,9 @@ use rustc_middle::{bug, mir, span_bug};
 use tracing::{instrument, trace};
 
 use super::{
-    AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult,
-    Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance,
-    Scalar, alloc_range, interp_ok, mir_assign_valid_types,
+    AllocInit, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx,
+    InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer,
+    Projectable, Provenance, Scalar, alloc_range, interp_ok, mir_assign_valid_types,
 };
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
@@ -983,7 +983,7 @@ where
         let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else {
             span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
         };
-        let ptr = self.allocate_ptr(size, align, kind)?;
+        let ptr = self.allocate_ptr(size, align, kind, AllocInit::Uninit)?;
         interp_ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false))
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 996142d7b03..8ecb3e13d5c 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -381,6 +381,7 @@ where
             OpaqueCast(ty) => {
                 span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
             }
+            UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?,
             // We don't want anything happening here, this is here as a dummy.
             Subtype(_) => base.transmute(base.layout(), self)?,
             Field(field, _) => self.project_field(base, field.index())?,
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index d9c0ff5acd1..abe73c43d8a 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -277,6 +277,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let discr = self.discriminant_for_variant(op.layout.ty, variant)?;
                 self.write_immediate(*discr, &dest)?;
             }
+
+            WrapUnsafeBinder(ref op, _ty) => {
+                // Constructing an unsafe binder acts like a transmute
+                // since the operand's layout does not change.
+                let op = self.eval_operand(op, None)?;
+                self.copy_op_allow_transmute(&op, &dest)?;
+            }
         }
 
         trace!("{:?}", self.dump_place(&dest));
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index af8d618b6b5..4cfaacebfcd 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -54,7 +54,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> &'tcx [VtblEntry<'tcx>] {
         if let Some(trait_) = trait_ {
             let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty);
-            let trait_ref = self.tcx.erase_regions(trait_ref);
+            let trait_ref =
+                self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
             self.tcx.vtable_entries(trait_ref)
         } else {
             TyCtxt::COMMON_VTABLE_ENTRIES
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index ecb7c3fc93c..eb98e3b5380 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -2,7 +2,7 @@ use std::ops::ControlFlow;
 
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir;
-use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer};
+use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer};
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
@@ -76,7 +76,7 @@ pub(crate) fn create_static_alloc<'tcx>(
     static_def_id: LocalDefId,
     layout: TyAndLayout<'tcx>,
 ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
-    let alloc = Allocation::try_uninit(layout.size, layout.align.abi)?;
+    let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit)?;
     let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into());
     assert_eq!(ecx.machine.static_root_ids, None);
     ecx.machine.static_root_ids = Some((alloc_id, static_def_id));
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index d75df1ad442..8e544798742 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1240,6 +1240,17 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
                     self.visit_field(val, 0, &self.ecx.project_index(val, 0)?)?;
                 }
             }
+            ty::Pat(base, pat) => {
+                // First check that the base type is valid
+                self.visit_value(&val.transmute(self.ecx.layout_of(*base)?, self.ecx)?)?;
+                // When you extend this match, make sure to also add tests to
+                // tests/ui/type/pattern_types/validity.rs((
+                match **pat {
+                    // Range patterns are precisely reflected into `valid_range` and thus
+                    // handled fully by `visit_scalar` (called below).
+                    ty::PatternKind::Range { .. } => {},
+                }
+            }
             _ => {
                 // default handler
                 try_validation!(
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index b5adf06b300..ecf9745b779 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -46,8 +46,13 @@ pub fn provide(providers: &mut Providers) {
     };
     providers.hooks.try_destructure_mir_constant_for_user_output =
         const_eval::try_destructure_mir_constant_for_user_output;
-    providers.valtree_to_const_val = |tcx, (ty, valtree)| {
-        const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), ty, valtree)
+    providers.valtree_to_const_val = |tcx, cv| {
+        const_eval::valtree_to_const_value(
+            tcx,
+            ty::TypingEnv::fully_monomorphized(),
+            cv.ty,
+            cv.valtree,
+        )
     };
     providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
         util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index 6dd9447cf5a..e926040e9ba 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -1,7 +1,6 @@
 use rustc_hir::LangItem;
-use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::Symbol;
 use tracing::trace;
@@ -48,15 +47,15 @@ fn alloc_caller_location<'tcx>(
 }
 
 pub(crate) fn const_caller_location_provider(
-    tcx: TyCtxtAt<'_>,
+    tcx: TyCtxt<'_>,
     file: Symbol,
     line: u32,
     col: u32,
 ) -> mir::ConstValue<'_> {
     trace!("const_caller_location: {}:{}:{}", file, line, col);
     let mut ecx = mk_eval_cx_to_read_const_val(
-        tcx.tcx,
-        tcx.span,
+        tcx,
+        rustc_span::DUMMY_SP, // FIXME: use a proper span here?
         ty::TypingEnv::fully_monomorphized(),
         CanAccessMutGlobal::No,
     );
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 65d586124b3..6ef73debadd 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -76,6 +76,7 @@ pub mod sync;
 pub mod tagged_ptr;
 pub mod temp_dir;
 pub mod thinvec;
+pub mod thousands;
 pub mod transitive_relation;
 pub mod unhash;
 pub mod unord;
diff --git a/compiler/rustc_data_structures/src/thousands/mod.rs b/compiler/rustc_data_structures/src/thousands/mod.rs
new file mode 100644
index 00000000000..e7ab7ec2932
--- /dev/null
+++ b/compiler/rustc_data_structures/src/thousands/mod.rs
@@ -0,0 +1,16 @@
+//! This is an extremely bare-bones alternative to the `thousands` crate on
+//! crates.io, for printing large numbers in a readable fashion.
+
+#[cfg(test)]
+mod tests;
+
+// Converts the number to a string, with underscores as the thousands separator.
+pub fn format_with_underscores(n: usize) -> String {
+    let mut s = n.to_string();
+    let mut i = s.len();
+    while i > 3 {
+        i -= 3;
+        s.insert(i, '_');
+    }
+    s
+}
diff --git a/compiler/rustc_data_structures/src/thousands/tests.rs b/compiler/rustc_data_structures/src/thousands/tests.rs
new file mode 100644
index 00000000000..906605d9a93
--- /dev/null
+++ b/compiler/rustc_data_structures/src/thousands/tests.rs
@@ -0,0 +1,14 @@
+use super::*;
+
+#[test]
+fn test_format_with_underscores() {
+    assert_eq!("0", format_with_underscores(0));
+    assert_eq!("1", format_with_underscores(1));
+    assert_eq!("99", format_with_underscores(99));
+    assert_eq!("345", format_with_underscores(345));
+    assert_eq!("1_000", format_with_underscores(1_000));
+    assert_eq!("12_001", format_with_underscores(12_001));
+    assert_eq!("999_999", format_with_underscores(999_999));
+    assert_eq!("1_000_000", format_with_underscores(1_000_000));
+    assert_eq!("12_345_678", format_with_underscores(12_345_678));
+}
diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs
index 2fc767b3750..b0970144c42 100644
--- a/compiler/rustc_driver_impl/src/args.rs
+++ b/compiler/rustc_driver_impl/src/args.rs
@@ -1,7 +1,6 @@
 use std::{env, error, fmt, fs, io};
 
 use rustc_session::EarlyDiagCtxt;
-use rustc_span::ErrorGuaranteed;
 
 /// Expands argfiles in command line arguments.
 #[derive(Default)]
@@ -118,22 +117,22 @@ pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<Stri
 ///
 /// This function is identical to [`env::args()`] except that it emits an error when it encounters
 /// non-Unicode arguments instead of panicking.
-pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Result<Vec<String>, ErrorGuaranteed> {
-    let mut res = Ok(Vec::new());
+pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Vec<String> {
+    let mut args = Vec::new();
+    let mut guar = Ok(());
     for (i, arg) in env::args_os().enumerate() {
         match arg.into_string() {
-            Ok(arg) => {
-                if let Ok(args) = &mut res {
-                    args.push(arg);
-                }
-            }
+            Ok(arg) => args.push(arg),
             Err(arg) => {
-                res =
+                guar =
                     Err(early_dcx.early_err(format!("argument {i} is not valid Unicode: {arg:?}")))
             }
         }
     }
-    res
+    if let Err(guar) = guar {
+        guar.raise_fatal();
+    }
+    args
 }
 
 #[derive(Debug)]
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 20be2144609..6ea14d15c14 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -160,7 +160,7 @@ pub trait Callbacks {
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &interface::Compiler,
-        _queries: &ast::Crate,
+        _krate: &mut ast::Crate,
     ) -> Compilation {
         Compilation::Continue
     }
@@ -311,13 +311,13 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
 
         // Parse the crate root source code (doesn't parse submodules yet)
         // Everything else is parsed during macro expansion.
-        let krate = passes::parse(sess);
+        let mut krate = passes::parse(sess);
 
         // If pretty printing is requested: Figure out the representation, print it and exit
         if let Some(pp_mode) = sess.opts.pretty {
             if pp_mode.needs_ast_map() {
                 create_and_enter_global_ctxt(compiler, krate, |tcx| {
-                    tcx.ensure().early_lint_checks(());
+                    tcx.ensure_ok().early_lint_checks(());
                     pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx });
                     passes::write_dep_info(tcx);
                 });
@@ -328,7 +328,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
             return early_exit();
         }
 
-        if callbacks.after_crate_root_parsing(compiler, &krate) == Compilation::Stop {
+        if callbacks.after_crate_root_parsing(compiler, &mut krate) == Compilation::Stop {
             return early_exit();
         }
 
@@ -365,7 +365,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
                 return early_exit();
             }
 
-            tcx.ensure().analysis(());
+            tcx.ensure_ok().analysis(());
 
             if callbacks.after_analysis(compiler, tcx) == Compilation::Stop {
                 return early_exit();
@@ -1212,9 +1212,9 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, FatalError> {
 
 /// Variant of `catch_fatal_errors` for the `interface::Result` return type
 /// that also computes the exit code.
-pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
+pub fn catch_with_exit_code(f: impl FnOnce()) -> i32 {
     match catch_fatal_errors(f) {
-        Ok(Ok(())) => EXIT_SUCCESS,
+        Ok(()) => EXIT_SUCCESS,
         _ => EXIT_FAILURE,
     }
 }
@@ -1499,10 +1499,8 @@ pub fn main() -> ! {
     install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
     install_ctrlc_handler();
 
-    let exit_code = catch_with_exit_code(|| {
-        run_compiler(&args::raw_args(&early_dcx)?, &mut callbacks);
-        Ok(())
-    });
+    let exit_code =
+        catch_with_exit_code(|| run_compiler(&args::raw_args(&early_dcx), &mut callbacks));
 
     if let Some(format) = callbacks.time_passes {
         let end_rss = get_resident_set_size();
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index 93f3d2ab911..9ace486fa56 100644
--- a/compiler/rustc_driver_impl/src/pretty.rs
+++ b/compiler/rustc_driver_impl/src/pretty.rs
@@ -7,6 +7,7 @@ use rustc_ast_pretty::pprust as pprust_ast;
 use rustc_middle::bug;
 use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_mir_build::thir::print::{thir_flat, thir_tree};
 use rustc_session::Session;
 use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode};
 use rustc_smir::rustc_internal::pretty::write_smir_pretty;
@@ -221,7 +222,7 @@ impl<'tcx> PrintExtra<'tcx> {
 
 pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
     if ppm.needs_analysis() {
-        ex.tcx().ensure().analysis(());
+        ex.tcx().ensure_ok().analysis(());
     }
 
     let (src, src_name) = get_source(sess);
@@ -313,7 +314,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
             tcx.dcx().abort_if_errors();
             debug!("pretty printing THIR tree");
             for did in tcx.hir().body_owners() {
-                let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did));
+                let _ = writeln!(out, "{:?}:\n{}\n", did, thir_tree(tcx, did));
             }
             out
         }
@@ -324,7 +325,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
             tcx.dcx().abort_if_errors();
             debug!("pretty printing THIR flat");
             for did in tcx.hir().body_owners() {
-                let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did));
+                let _ = writeln!(out, "{:?}:\n{}\n", did, thir_flat(tcx, did));
             }
             out
         }
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 797dcd7b4d1..29a74ed3f4e 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
 use std::panic;
+use std::path::PathBuf;
 use std::thread::panicking;
 
 use rustc_data_structures::fx::FxIndexMap;
@@ -301,6 +302,7 @@ pub struct DiagInner {
 
     pub is_lint: Option<IsLint>,
 
+    pub long_ty_path: Option<PathBuf>,
     /// With `-Ztrack_diagnostics` enabled,
     /// we print where in rustc this error was emitted.
     pub(crate) emitted_at: DiagLocation,
@@ -324,6 +326,7 @@ impl DiagInner {
             args: Default::default(),
             sort_span: DUMMY_SP,
             is_lint: None,
+            long_ty_path: None,
             emitted_at: DiagLocation::caller(),
         }
     }
@@ -641,7 +644,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         found_label: &dyn fmt::Display,
         found: DiagStyledString,
     ) -> &mut Self {
-        self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
+        self.note_expected_found_extra(
+            expected_label,
+            expected,
+            found_label,
+            found,
+            DiagStyledString::normal(""),
+            DiagStyledString::normal(""),
+        )
     }
 
     #[rustc_lint_diagnostics]
@@ -651,8 +661,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         expected: DiagStyledString,
         found_label: &dyn fmt::Display,
         found: DiagStyledString,
-        expected_extra: &dyn fmt::Display,
-        found_extra: &dyn fmt::Display,
+        expected_extra: DiagStyledString,
+        found_extra: DiagStyledString,
     ) -> &mut Self {
         let expected_label = expected_label.to_string();
         let expected_label = if expected_label.is_empty() {
@@ -677,10 +687,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
             expected_label
         ))];
         msg.extend(expected.0);
-        msg.push(StringPart::normal(format!("`{expected_extra}\n")));
+        msg.push(StringPart::normal(format!("`")));
+        msg.extend(expected_extra.0);
+        msg.push(StringPart::normal(format!("\n")));
         msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
         msg.extend(found.0);
-        msg.push(StringPart::normal(format!("`{found_extra}")));
+        msg.push(StringPart::normal(format!("`")));
+        msg.extend(found_extra.0);
 
         // For now, just attach these as notes.
         self.highlighted_note(msg);
@@ -1293,9 +1306,37 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
     /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on
     /// `self`.
     fn take_diag(&mut self) -> DiagInner {
+        if let Some(path) = &self.long_ty_path {
+            self.note(format!(
+                "the full name for the type has been written to '{}'",
+                path.display()
+            ));
+            self.note("consider using `--verbose` to print the full type name to the console");
+        }
         Box::into_inner(self.diag.take().unwrap())
     }
 
+    /// This method allows us to access the path of the file where "long types" are written to.
+    ///
+    /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set,
+    /// and if it has been then we add a note mentioning the file where the "long types" were
+    /// written to.
+    ///
+    /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing
+    /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that
+    /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the
+    /// user where we wrote the file to is only printed once at most, *and* it makes it much harder
+    /// to forget to set it.
+    ///
+    /// If the diagnostic hasn't been created before a "short ty string" is created, then you should
+    /// ensure that this method is called to set it `*diag.long_ty_path() = path`.
+    ///
+    /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a
+    /// scope, `diag.long_ty_path()` should be called once somewhere close by.
+    pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
+        &mut self.long_ty_path
+    }
+
     /// Most `emit_producing_guarantee` functions use this as a starting point.
     fn emit_producing_nothing(mut self) {
         let diag = self.take_diag();
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 991dfa1821a..d0b4211c351 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -35,8 +35,8 @@ use crate::snippet::{
 use crate::styled_buffer::StyledBuffer;
 use crate::translation::{Translate, to_fluent_args};
 use crate::{
-    CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle,
-    Level, MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl,
+    CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level,
+    MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl,
 };
 
 /// Default column width, used in tests and when terminal dimensions cannot be determined.
@@ -537,11 +537,10 @@ impl Emitter for HumanEmitter {
 }
 
 /// An emitter that does nothing when emitting a non-fatal diagnostic.
-/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent
+/// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent
 /// failures of rustc, as witnessed e.g. in issue #89358.
 pub struct SilentEmitter {
-    pub fallback_bundle: LazyFallbackBundle,
-    pub fatal_dcx: DiagCtxt,
+    pub fatal_emitter: Box<dyn Emitter + DynSend>,
     pub fatal_note: Option<String>,
     pub emit_fatal_diagnostic: bool,
 }
@@ -552,9 +551,7 @@ impl Translate for SilentEmitter {
     }
 
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
-        // Ideally this field wouldn't be necessary and the fallback bundle in `fatal_dcx` would be
-        // used but the lock prevents this.
-        &self.fallback_bundle
+        self.fatal_emitter.fallback_fluent_bundle()
     }
 }
 
@@ -563,12 +560,12 @@ impl Emitter for SilentEmitter {
         None
     }
 
-    fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) {
+    fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) {
         if self.emit_fatal_diagnostic && diag.level == Level::Fatal {
             if let Some(fatal_note) = &self.fatal_note {
                 diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new());
             }
-            self.fatal_dcx.handle().emit_diagnostic(diag);
+            self.fatal_emitter.emit_diagnostic(diag, registry);
         }
     }
 }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 549729548f5..7a02e0dd2f0 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -59,13 +59,13 @@ use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
 use rustc_data_structures::AtomicRef;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
-use rustc_data_structures::sync::Lock;
+use rustc_data_structures::sync::{DynSend, Lock};
 pub use rustc_error_messages::{
     DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel,
     SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
 };
 use rustc_lint_defs::LintExpectationId;
-pub use rustc_lint_defs::{Applicability, pluralize};
+pub use rustc_lint_defs::{Applicability, listify, pluralize};
 use rustc_macros::{Decodable, Encodable};
 pub use rustc_span::ErrorGuaranteed;
 pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
@@ -676,57 +676,44 @@ impl DiagCtxt {
         Self { inner: Lock::new(DiagCtxtInner::new(emitter)) }
     }
 
-    pub fn make_silent(
-        &self,
-        fallback_bundle: LazyFallbackBundle,
-        fatal_note: Option<String>,
-        emit_fatal_diagnostic: bool,
-    ) {
-        self.wrap_emitter(|old_dcx| {
-            Box::new(emitter::SilentEmitter {
-                fallback_bundle,
-                fatal_dcx: DiagCtxt { inner: Lock::new(old_dcx) },
-                fatal_note,
-                emit_fatal_diagnostic,
-            })
-        });
-    }
-
-    fn wrap_emitter<F>(&self, f: F)
-    where
-        F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>,
-    {
-        // A empty type that implements `Emitter` so that a `DiagCtxtInner` can be constructed
-        // to temporarily swap in place of the real one, which will be used in constructing
-        // its replacement.
+    pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) {
+        // An empty type that implements `Emitter` to temporarily swap in place of the real one,
+        // which will be used in constructing its replacement.
         struct FalseEmitter;
 
         impl Emitter for FalseEmitter {
             fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) {
-                unimplemented!("false emitter must only used during `wrap_emitter`")
+                unimplemented!("false emitter must only used during `make_silent`")
             }
 
             fn source_map(&self) -> Option<&SourceMap> {
-                unimplemented!("false emitter must only used during `wrap_emitter`")
+                unimplemented!("false emitter must only used during `make_silent`")
             }
         }
 
         impl translation::Translate for FalseEmitter {
             fn fluent_bundle(&self) -> Option<&FluentBundle> {
-                unimplemented!("false emitter must only used during `wrap_emitter`")
+                unimplemented!("false emitter must only used during `make_silent`")
             }
 
             fn fallback_fluent_bundle(&self) -> &FluentBundle {
-                unimplemented!("false emitter must only used during `wrap_emitter`")
+                unimplemented!("false emitter must only used during `make_silent`")
             }
         }
 
         let mut inner = self.inner.borrow_mut();
-        let mut prev_dcx = DiagCtxtInner::new(Box::new(FalseEmitter));
-        std::mem::swap(&mut *inner, &mut prev_dcx);
-        let new_emitter = f(prev_dcx);
-        let mut new_dcx = DiagCtxtInner::new(new_emitter);
-        std::mem::swap(&mut *inner, &mut new_dcx);
+        let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>;
+        std::mem::swap(&mut inner.emitter, &mut prev_emitter);
+        let new_emitter = Box::new(emitter::SilentEmitter {
+            fatal_emitter: prev_emitter,
+            fatal_note,
+            emit_fatal_diagnostic,
+        });
+        inner.emitter = new_emitter;
+    }
+
+    pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) {
+        self.inner.borrow_mut().emitter = emitter;
     }
 
     /// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
@@ -1999,18 +1986,6 @@ pub fn a_or_an(s: &str) -> &'static str {
     }
 }
 
-/// 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 {
-        [] => "".to_string(),
-        [a] => a.to_string(),
-        [a, b] => format!("{a} and {b}"),
-        [a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)),
-    }
-}
-
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum TerminalUrl {
     No,
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 17433eed9e7..e0543977e98 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -616,7 +616,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
     ),
     rustc_attr!(
-        rustc_allowed_through_unstable_modules, Normal, template!(Word, NameValueStr: "deprecation message"),
+        rustc_allowed_through_unstable_modules, Normal, template!(NameValueStr: "deprecation message"),
         WarnFollowing, EncodeCrossCrate::No,
         "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
         through unstable paths"
@@ -1136,7 +1136,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     rustc_attr!(
         TEST, rustc_dump_vtable, Normal, template!(Word),
-        WarnFollowing, EncodeCrossCrate::Yes
+        WarnFollowing, EncodeCrossCrate::No
     ),
     rustc_attr!(
         TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a396d705cbb..af2f86b67e0 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1437,7 +1437,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
-            Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
+            Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true,
             Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
             Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
@@ -1464,7 +1464,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
-            Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
+            Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
             Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
             Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
@@ -1618,9 +1618,6 @@ pub enum PatKind<'hir> {
     /// A never pattern `!`.
     Never,
 
-    /// A path pattern for a unit struct/variant or a (maybe-associated) constant.
-    Path(QPath<'hir>),
-
     /// A tuple pattern (e.g., `(a, b)`).
     /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
     /// `0 <= position <= subpats.len()`
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index b0d80d0f809..31764ab1209 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -709,9 +709,6 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
             try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
             walk_list!(visitor, visit_pat, children);
         }
-        PatKind::Path(ref qpath) => {
-            try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
-        }
         PatKind::Struct(ref qpath, fields, _) => {
             try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
             walk_list!(visitor, visit_pat_field, fields);
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 02bc069fc5f..d9759580e8f 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -316,6 +316,7 @@ language_item_table! {
     PanicAsyncFnResumedPanic, sym::panic_const_async_fn_resumed_panic, panic_const_async_fn_resumed_panic, Target::Fn, GenericRequirement::None;
     PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None;
     PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None;
+    PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None;
     /// libstd panic entry point. Necessary for const eval to be able to catch it
     BeginPanic,              sym::begin_panic,         begin_panic_fn,             Target::Fn,             GenericRequirement::None;
 
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index bb853985c7d..8dd1e4e8292 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -105,7 +105,10 @@ impl hir::Pat<'_> {
         let mut variants = vec![];
         self.walk(|p| match &p.kind {
             PatKind::Or(_) => false,
-            PatKind::Path(hir::QPath::Resolved(_, path))
+            PatKind::Expr(hir::PatExpr {
+                kind: hir::PatExprKind::Path(hir::QPath::Resolved(_, path)),
+                ..
+            })
             | PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..)
             | PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
                 if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) =
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index be4004f5904..a4b5a87361e 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -234,6 +234,9 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a
     .help = consider moving this inherent impl into the crate defining the type if possible
     .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
 
+hir_analysis_invalid_base_type = `{$ty}` is not a valid base type for range patterns
+    .note = range patterns only support integers
+
 hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}`
     .note = type of `self` must not be a method generic parameter type
 
@@ -438,7 +441,6 @@ hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pat
     .label = this type is the same as the inner type without a pattern
 hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
     .label = not allowed in type signatures
-
 hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
     .label = `Self` is not a generic argument, but an alias to the type of the {$what}
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index b0a6922ff72..6c534d58a7d 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -27,7 +27,6 @@ use rustc_session::lint::builtin::UNINHABITED_STATIC;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
 use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_type_ir::fold::TypeFoldable;
 use tracing::{debug, instrument};
 use ty::TypingMode;
@@ -417,9 +416,7 @@ fn check_opaque_meets_bounds<'tcx>(
     }
 
     let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, defining_use_anchor)?;
-    let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys);
-    let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
-    ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
+    ocx.resolve_regions_and_report_errors(defining_use_anchor, param_env, wf_tys)?;
 
     if infcx.next_trait_solver() {
         Ok(())
@@ -781,13 +778,13 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     match tcx.def_kind(def_id) {
         DefKind::Static { .. } => {
-            tcx.ensure().typeck(def_id);
+            tcx.ensure_ok().typeck(def_id);
             maybe_check_static_with_link_section(tcx, def_id);
             check_static_inhabited(tcx, def_id);
             check_static_linkage(tcx, def_id);
         }
         DefKind::Const => {
-            tcx.ensure().typeck(def_id);
+            tcx.ensure_ok().typeck(def_id);
         }
         DefKind::Enum => {
             check_enum(tcx, def_id);
@@ -807,7 +804,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         DefKind::Impl { of_trait } => {
             if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) {
                 if tcx
-                    .ensure()
+                    .ensure_ok()
                     .coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id)
                     .is_ok()
                 {
@@ -1045,7 +1042,7 @@ fn check_impl_items_against_trait<'tcx>(
             continue;
         };
 
-        let res = tcx.ensure().compare_impl_item(impl_item.expect_local());
+        let res = tcx.ensure_ok().compare_impl_item(impl_item.expect_local());
 
         if res.is_ok() {
             match ty_impl_item.kind {
@@ -1491,7 +1488,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
     for v in def.variants() {
         if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
-            tcx.ensure().typeck(discr_def_id.expect_local());
+            tcx.ensure_ok().typeck(discr_def_id.expect_local());
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index d2ab98bae89..a91d72e9225 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -9,7 +9,6 @@ use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_e
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::VisitorExt;
 use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -24,7 +23,6 @@ use rustc_span::Span;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
-use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
 };
@@ -416,11 +414,7 @@ fn compare_method_predicate_entailment<'tcx>(
 
     // Finally, resolve all regions. This catches wily misuses of
     // lifetime parameters.
-    let outlives_env = OutlivesEnvironment::with_bounds(
-        param_env,
-        infcx.implied_bounds_tys(param_env, impl_m_def_id, &wf_tys),
-    );
-    let errors = infcx.resolve_regions(&outlives_env);
+    let errors = infcx.resolve_regions(impl_m_def_id, param_env, wf_tys);
     if !errors.is_empty() {
         return Err(infcx
             .tainted_by_errors()
@@ -430,12 +424,12 @@ fn compare_method_predicate_entailment<'tcx>(
     Ok(())
 }
 
-struct RemapLateParam<'a, 'tcx> {
+struct RemapLateParam<'tcx> {
     tcx: TyCtxt<'tcx>,
-    mapping: &'a FxIndexMap<ty::LateParamRegionKind, ty::LateParamRegionKind>,
+    mapping: FxIndexMap<ty::LateParamRegionKind, ty::LateParamRegionKind>,
 }
 
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'_, 'tcx> {
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'tcx> {
     fn cx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -659,6 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
                 }))),
                 terr,
                 false,
+                None,
             );
             return Err(diag.emit());
         }
@@ -725,11 +720,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
 
     // Finally, resolve all regions. This catches wily misuses of
     // lifetime parameters.
-    let outlives_env = OutlivesEnvironment::with_bounds(
-        param_env,
-        infcx.implied_bounds_tys(param_env, impl_m_def_id, &wf_tys),
-    );
-    ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?;
+    ocx.resolve_regions_and_report_errors(impl_m_def_id, param_env, wf_tys)?;
 
     let mut remapped_types = DefIdMap::default();
     for (def_id, (ty, args)) in collected_types {
@@ -1080,6 +1071,7 @@ fn report_trait_method_mismatch<'tcx>(
         }))),
         terr,
         false,
+        None,
     );
 
     diag.emit()
@@ -1872,6 +1864,7 @@ fn compare_const_predicate_entailment<'tcx>(
             }))),
             terr,
             false,
+            None,
         );
         return Err(diag.emit());
     };
@@ -1883,8 +1876,7 @@ fn compare_const_predicate_entailment<'tcx>(
         return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
     }
 
-    let outlives_env = OutlivesEnvironment::new(param_env);
-    ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env)
+    ocx.resolve_regions_and_report_errors(impl_ct_def_id, param_env, [])
 }
 
 #[instrument(level = "debug", skip(tcx))]
@@ -2017,8 +2009,7 @@ fn compare_type_predicate_entailment<'tcx>(
 
     // Finally, resolve all regions. This catches wily misuses of
     // lifetime parameters.
-    let outlives_env = OutlivesEnvironment::new(param_env);
-    ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
+    ocx.resolve_regions_and_report_errors(impl_ty_def_id, param_env, [])
 }
 
 /// Validate that `ProjectionCandidate`s created for this associated type will
@@ -2043,7 +2034,7 @@ pub(super) fn check_type_bounds<'tcx>(
 ) -> Result<(), ErrorGuaranteed> {
     // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
     // other `Foo` impls are incoherent.
-    tcx.ensure().coherent_trait(impl_trait_ref.def_id)?;
+    tcx.ensure_ok().coherent_trait(impl_trait_ref.def_id)?;
 
     let param_env = tcx.param_env(impl_ty.def_id);
     debug!(?param_env);
@@ -2147,9 +2138,7 @@ pub(super) fn check_type_bounds<'tcx>(
 
     // Finally, resolve all regions. This catches wily misuses of
     // lifetime parameters.
-    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, &assumed_wf_types);
-    let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
-    ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
+    ocx.resolve_regions_and_report_errors(impl_ty_def_id, param_env, assumed_wf_types)
 }
 
 struct ReplaceTy<'tcx> {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index 2b14594ea1b..0e9e9b48ab3 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
 use rustc_middle::span_bug;
 use rustc_middle::traits::ObligationCause;
@@ -13,7 +12,6 @@ use rustc_middle::ty::{
 };
 use rustc_span::Span;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
-use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt;
 use rustc_trait_selection::traits::{ObligationCtxt, elaborate, normalize_param_env_or_error};
 
 /// Check that an implementation does not refine an RPITIT from a trait method signature.
@@ -170,11 +168,7 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
         tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (selection)");
         return;
     }
-    let outlives_env = OutlivesEnvironment::with_bounds(
-        param_env,
-        infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), &implied_wf_types),
-    );
-    let errors = infcx.resolve_regions(&outlives_env);
+    let errors = infcx.resolve_regions(impl_m.def_id.expect_local(), param_env, implied_wf_types);
     if !errors.is_empty() {
         tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (regions)");
         return;
@@ -305,8 +299,7 @@ fn report_mismatched_rpitit_signature<'tcx>(
     })
     .collect();
 
-    let mut return_ty =
-        trait_m_sig.output().fold_with(&mut super::RemapLateParam { tcx, mapping: &mapping });
+    let mut return_ty = trait_m_sig.output().fold_with(&mut super::RemapLateParam { tcx, mapping });
 
     if tcx.asyncness(impl_m_def_id).is_async() && tcx.asyncness(trait_m_def_id).is_async() {
         let ty::Alias(ty::Projection, future_ty) = return_ty.kind() else {
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 1c9bbe627fb..d7dfe482da4 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -1,11 +1,6 @@
-// FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
-//
-// We don't do any drop checking during hir typeck.
-
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::codes::*;
 use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::util::CheckRegions;
@@ -33,7 +28,10 @@ use crate::hir::def_id::{DefId, LocalDefId};
 ///    struct/enum definition for the nominal type itself (i.e.
 ///    cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
 ///
-pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorGuaranteed> {
+pub(crate) fn check_drop_impl(
+    tcx: TyCtxt<'_>,
+    drop_impl_did: DefId,
+) -> Result<(), ErrorGuaranteed> {
     match tcx.impl_polarity(drop_impl_did) {
         ty::ImplPolarity::Positive => {}
         ty::ImplPolarity::Negative => {
@@ -192,7 +190,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
         return Err(guar.unwrap());
     }
 
-    let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(adt_env));
+    let errors = ocx.infcx.resolve_regions(adt_def_id, adt_env, []);
     if !errors.is_empty() {
         let mut guar = None;
         for error in errors {
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 8aa95d1c1d5..cf3d4897304 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -199,7 +199,8 @@ pub fn check_intrinsic_type(
         let split: Vec<&str> = name_str.split('_').collect();
         assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
 
-        //We only care about the operation here
+        // Each atomic op has variants with different suffixes (`_seq_cst`, `_acquire`, etc.). Use
+        // string ops to strip the suffixes, because the variants all get the same treatment here.
         let (n_tps, inputs, output) = match split[1] {
             "cxchg" | "cxchgweak" => (
                 1,
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index cc0b7fdd8dd..96b33bdd250 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -80,7 +80,6 @@ use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_index::bit_set::DenseBitSet;
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, TyCtxtInferExt as _};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::query::Providers;
@@ -456,18 +455,14 @@ fn fn_sig_suggestion<'tcx>(
     let mut output = sig.output();
 
     let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
-        output = if let ty::Alias(_, alias_ty) = *output.kind() {
-            tcx.explicit_item_self_bounds(alias_ty.def_id)
+        output = if let ty::Alias(_, alias_ty) = *output.kind()
+            && let Some(output) = tcx
+                .explicit_item_self_bounds(alias_ty.def_id)
                 .iter_instantiated_copied(tcx, alias_ty.args)
                 .find_map(|(bound, _)| {
                     bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
-                })
-                .unwrap_or_else(|| {
-                    span_bug!(
-                        ident.span,
-                        "expected async fn to have `impl Future` output, but it returns {output}"
-                    )
-                })
+                }) {
+            output
         } else {
             span_bug!(
                 ident.span,
@@ -650,13 +645,13 @@ pub fn check_function_signature<'tcx>(
                 }))),
                 err,
                 false,
+                None,
             );
             return Err(diag.emit());
         }
     }
 
-    let outlives_env = OutlivesEnvironment::new(param_env);
-    if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, &outlives_env) {
+    if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {
         return Err(e);
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 83c69dc2ef4..d43c65c0023 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -703,7 +703,6 @@ fn resolve_local<'tcx>(
             | PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
             | PatKind::Wild
             | PatKind::Never
-            | PatKind::Path(_)
             | PatKind::Expr(_)
             | PatKind::Range(_, _, _)
             | PatKind::Err(_) => false,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index cd19993f937..a90e034ba4a 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -25,11 +25,10 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::parse::feature_err;
 use rustc_span::{DUMMY_SP, Ident, Span, sym};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
-use rustc_trait_selection::regions::InferCtxtRegionExt;
+use rustc_trait_selection::regions::{InferCtxtRegionExt, OutlivesEnvironmentBuildExt};
 use rustc_trait_selection::traits::misc::{
     ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty,
 };
-use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
@@ -128,13 +127,17 @@ where
     let infcx_compat = infcx.fork();
 
     // We specifically want to call the non-compat version of `implied_bounds_tys`; we do this always.
-    let implied_bounds =
-        infcx.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, false);
-    let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
+    let outlives_env = OutlivesEnvironment::new_with_implied_bounds_compat(
+        &infcx,
+        body_def_id,
+        param_env,
+        assumed_wf_types.iter().copied(),
+        false,
+    );
 
     lint_redundant_lifetimes(tcx, body_def_id, &outlives_env);
 
-    let errors = infcx.resolve_regions(&outlives_env);
+    let errors = infcx.resolve_regions_with_outlives_env(&outlives_env);
     if errors.is_empty() {
         return Ok(());
     }
@@ -172,10 +175,14 @@ where
     // but that does result in slightly more work when this option is set and
     // just obscures what we mean here anyways. Let's just be explicit.
     if is_bevy && !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat {
-        let implied_bounds =
-            infcx_compat.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, true);
-        let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
-        let errors_compat = infcx_compat.resolve_regions(&outlives_env);
+        let outlives_env = OutlivesEnvironment::new_with_implied_bounds_compat(
+            &infcx,
+            body_def_id,
+            param_env,
+            assumed_wf_types,
+            true,
+        );
+        let errors_compat = infcx_compat.resolve_regions_with_outlives_env(&outlives_env);
         if errors_compat.is_empty() {
             Ok(())
         } else {
@@ -321,16 +328,20 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
         hir::ItemKind::TraitAlias(..) => check_trait(tcx, item),
         // `ForeignItem`s are handled separately.
         hir::ItemKind::ForeignMod { .. } => Ok(()),
-        hir::ItemKind::TyAlias(hir_ty, hir_generics) => {
-            if tcx.type_alias_is_lazy(item.owner_id) {
-                // Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
-                // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
-                let res = check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
-                check_variances_for_type_defn(tcx, item, hir_generics);
-                res
-            } else {
+        hir::ItemKind::TyAlias(hir_ty, hir_generics) if tcx.type_alias_is_lazy(item.owner_id) => {
+            let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
+                let ty = tcx.type_of(def_id).instantiate_identity();
+                let item_ty = wfcx.normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty);
+                wfcx.register_wf_obligation(
+                    hir_ty.span,
+                    Some(WellFormedLoc::Ty(def_id)),
+                    item_ty.into(),
+                );
+                check_where_clauses(wfcx, item.span, def_id);
                 Ok(())
-            }
+            });
+            check_variances_for_type_defn(tcx, item, hir_generics);
+            res
         }
         _ => Ok(()),
     };
@@ -769,12 +780,7 @@ fn test_region_obligations<'tcx>(
 
     add_constraints(&infcx);
 
-    let outlives_environment = OutlivesEnvironment::with_bounds(
-        param_env,
-        infcx.implied_bounds_tys(param_env, id, wf_tys),
-    );
-
-    let errors = infcx.resolve_regions(&outlives_environment);
+    let errors = infcx.resolve_regions(id, param_env, wf_tys.iter().copied());
     debug!(?errors, "errors");
 
     // If we were able to prove that the type outlives the region without
@@ -1044,7 +1050,7 @@ fn check_associated_item(
 
         // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
         // other `Foo` impls are incoherent.
-        tcx.ensure()
+        tcx.ensure_ok()
             .coherent_trait(tcx.parent(item.trait_item_def_id.unwrap_or(item_id.into())))?;
 
         let self_ty = match item.container {
@@ -1274,7 +1280,6 @@ fn check_item_fn(
 
 enum UnsizedHandling {
     Forbid,
-    Allow,
     AllowIfForeignTail,
 }
 
@@ -1292,7 +1297,6 @@ fn check_item_type(
 
         let forbid_unsized = match unsized_handling {
             UnsizedHandling::Forbid => true,
-            UnsizedHandling::Allow => false,
             UnsizedHandling::AllowIfForeignTail => {
                 let tail =
                     tcx.struct_tail_for_codegen(item_ty, wfcx.infcx.typing_env(wfcx.param_env));
@@ -1352,7 +1356,7 @@ fn check_impl<'tcx>(
                 let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().instantiate_identity();
                 // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
                 // other `Foo` impls are incoherent.
-                tcx.ensure().coherent_trait(trait_ref.def_id)?;
+                tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
                 let trait_span = hir_trait_ref.path.span;
                 let trait_ref = wfcx.normalize(
                     trait_span,
@@ -2265,14 +2269,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
 
 fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
     let items = tcx.hir_module_items(module);
-    let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id));
-    res =
-        res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
-    res =
-        res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
-    res = res
-        .and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
-    res = res.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item)));
+    let res = items
+        .par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))
+        .and(items.par_impl_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
+        .and(items.par_trait_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
+        .and(
+            items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)),
+        )
+        .and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item)));
     if module == LocalModDefId::CRATE_DEF_ID {
         super::entry::check_for_entry_fn(tcx);
     }
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 27a7c2ea530..3511dbc6252 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -10,7 +10,6 @@ use rustc_hir as hir;
 use rustc_hir::ItemKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
@@ -193,7 +192,7 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E
     // errors; other parts of the code may demand it for the info of
     // course.
     let span = tcx.def_span(impl_did);
-    tcx.at(span).ensure().coerce_unsized_info(impl_did)
+    tcx.at(span).ensure_ok().coerce_unsized_info(impl_did)
 }
 
 fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
@@ -346,8 +345,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
                 }
 
                 // Finally, resolve all regions.
-                let outlives_env = OutlivesEnvironment::new(param_env);
-                res = res.and(ocx.resolve_regions_and_report_errors(impl_did, &outlives_env));
+                res = res.and(ocx.resolve_regions_and_report_errors(impl_did, param_env, []));
             }
             res
         }
@@ -406,17 +404,12 @@ pub(crate) fn coerce_unsized_info<'tcx>(
             check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
         }
 
-        (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl(
-            ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a },
-            ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b },
-            &|ty| Ty::new_imm_ptr(tcx, ty),
-        ),
-
-        (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl(
-            ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a },
-            ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b },
-            &|ty| Ty::new_imm_ptr(tcx, ty),
-        ),
+        (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
+        | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
+            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
+            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
+            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
+        }
 
         (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
             if def_a.is_struct() && def_b.is_struct() =>
@@ -564,8 +557,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
     }
 
     // Finally, resolve all regions.
-    let outlives_env = OutlivesEnvironment::new(param_env);
-    let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
+    let _ = ocx.resolve_regions_and_report_errors(impl_did, param_env, []);
 
     Ok(CoerceUnsizedInfo { custom_kind: kind })
 }
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 4e5f0a3186a..1bc60087ab5 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -151,19 +151,19 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
     let Some(impls) = tcx.all_local_trait_impls(()).get(&def_id) else { return Ok(()) };
     // Trigger building the specialization graph for the trait. This will detect and report any
     // overlap errors.
-    let mut res = tcx.ensure().specialization_graph_of(def_id);
+    let mut res = tcx.ensure_ok().specialization_graph_of(def_id);
 
     for &impl_def_id in impls {
         let trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
         let trait_ref = trait_header.trait_ref.instantiate_identity();
         let trait_def = tcx.trait_def(trait_ref.def_id);
 
-        res = res.and(check_impl(tcx, impl_def_id, trait_ref, trait_def));
-        res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref));
-
-        res = res.and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def));
-        res = res.and(tcx.ensure().orphan_check_impl(impl_def_id));
-        res = res.and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header));
+        res = res
+            .and(check_impl(tcx, impl_def_id, trait_ref, trait_def))
+            .and(check_object_overlap(tcx, impl_def_id, trait_ref))
+            .and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def))
+            .and(tcx.ensure_ok().orphan_check_impl(impl_def_id))
+            .and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header));
     }
 
     res
@@ -199,10 +199,9 @@ fn check_object_overlap<'tcx>(
 
         for component_def_id in component_def_ids {
             if !tcx.is_dyn_compatible(component_def_id) {
-                // FIXME(dyn_compat_renaming): Rename test and update comment.
                 // Without the 'dyn_compatible_for_dispatch' feature this is an error
                 // which will be reported by wfcheck. Ignore it here.
-                // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
+                // This is tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`.
                 // With the feature enabled, the trait is not implemented automatically,
                 // so this is valid.
             } else {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index cad7b2a1e57..ce7319f6561 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -57,7 +57,7 @@ mod type_of;
 
 ///////////////////////////////////////////////////////////////////////////
 
-pub fn provide(providers: &mut Providers) {
+pub(crate) fn provide(providers: &mut Providers) {
     resolve_bound_vars::provide(providers);
     *providers = Providers {
         type_of: type_of::type_of,
@@ -122,7 +122,7 @@ pub fn provide(providers: &mut Providers) {
 /// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy
 /// `probe_ty_param_bounds` requests, drawing the information from
 /// the HIR (`hir::Generics`), recursively.
-pub struct ItemCtxt<'tcx> {
+pub(crate) struct ItemCtxt<'tcx> {
     tcx: TyCtxt<'tcx>,
     item_def_id: LocalDefId,
     tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
@@ -148,7 +148,7 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector {
     }
 }
 
-pub struct CollectItemTypesVisitor<'tcx> {
+pub(crate) struct CollectItemTypesVisitor<'tcx> {
     pub tcx: TyCtxt<'tcx>,
 }
 
@@ -292,16 +292,16 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
             match param.kind {
                 hir::GenericParamKind::Lifetime { .. } => {}
                 hir::GenericParamKind::Type { default: Some(_), .. } => {
-                    self.tcx.ensure().type_of(param.def_id);
+                    self.tcx.ensure_ok().type_of(param.def_id);
                 }
                 hir::GenericParamKind::Type { .. } => {}
                 hir::GenericParamKind::Const { default, .. } => {
-                    self.tcx.ensure().type_of(param.def_id);
+                    self.tcx.ensure_ok().type_of(param.def_id);
                     if let Some(default) = default {
                         // need to store default and type of default
-                        self.tcx.ensure().const_param_default(param.def_id);
+                        self.tcx.ensure_ok().const_param_default(param.def_id);
                         if let hir::ConstArgKind::Anon(ac) = default.kind {
-                            self.tcx.ensure().type_of(ac.def_id);
+                            self.tcx.ensure_ok().type_of(ac.def_id);
                         }
                     }
                 }
@@ -312,8 +312,8 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::ExprKind::Closure(closure) = expr.kind {
-            self.tcx.ensure().generics_of(closure.def_id);
-            self.tcx.ensure().codegen_fn_attrs(closure.def_id);
+            self.tcx.ensure_ok().generics_of(closure.def_id);
+            self.tcx.ensure_ok().codegen_fn_attrs(closure.def_id);
             // We do not call `type_of` for closures here as that
             // depends on typecheck and would therefore hide
             // any further errors in case one typeck fails.
@@ -325,15 +325,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
     /// `check_item_type` ensures that it's called instead.
     fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) {
         let def_id = opaque.def_id;
-        self.tcx.ensure().generics_of(def_id);
-        self.tcx.ensure().predicates_of(def_id);
-        self.tcx.ensure().explicit_item_bounds(def_id);
-        self.tcx.ensure().explicit_item_self_bounds(def_id);
-        self.tcx.ensure().item_bounds(def_id);
-        self.tcx.ensure().item_self_bounds(def_id);
+        self.tcx.ensure_ok().generics_of(def_id);
+        self.tcx.ensure_ok().predicates_of(def_id);
+        self.tcx.ensure_ok().explicit_item_bounds(def_id);
+        self.tcx.ensure_ok().explicit_item_self_bounds(def_id);
+        self.tcx.ensure_ok().item_bounds(def_id);
+        self.tcx.ensure_ok().item_self_bounds(def_id);
         if self.tcx.is_conditionally_const(def_id) {
-            self.tcx.ensure().explicit_implied_const_bounds(def_id);
-            self.tcx.ensure().const_conditions(def_id);
+            self.tcx.ensure_ok().explicit_implied_const_bounds(def_id);
+            self.tcx.ensure_ok().const_conditions(def_id);
         }
         intravisit::walk_opaque_ty(self, opaque);
     }
@@ -364,19 +364,19 @@ fn bad_placeholder<'cx, 'tcx>(
 }
 
 impl<'tcx> ItemCtxt<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
+    pub(crate) fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
         ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) }
     }
 
-    pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+    pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
         self.lowerer().lower_ty(hir_ty)
     }
 
-    pub fn hir_id(&self) -> hir::HirId {
+    pub(crate) fn hir_id(&self) -> hir::HirId {
         self.tcx.local_def_id_to_hir_id(self.item_def_id)
     }
 
-    pub fn node(&self) -> hir::Node<'tcx> {
+    pub(crate) fn node(&self) -> hir::Node<'tcx> {
         self.tcx.hir_node(self.hir_id())
     }
 
@@ -683,20 +683,20 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
         hir::ItemKind::ForeignMod { items, .. } => {
             for item in *items {
                 let item = tcx.hir().foreign_item(item.id);
-                tcx.ensure().generics_of(item.owner_id);
-                tcx.ensure().type_of(item.owner_id);
-                tcx.ensure().predicates_of(item.owner_id);
+                tcx.ensure_ok().generics_of(item.owner_id);
+                tcx.ensure_ok().type_of(item.owner_id);
+                tcx.ensure_ok().predicates_of(item.owner_id);
                 if tcx.is_conditionally_const(def_id) {
-                    tcx.ensure().explicit_implied_const_bounds(def_id);
-                    tcx.ensure().const_conditions(def_id);
+                    tcx.ensure_ok().explicit_implied_const_bounds(def_id);
+                    tcx.ensure_ok().const_conditions(def_id);
                 }
                 match item.kind {
                     hir::ForeignItemKind::Fn(..) => {
-                        tcx.ensure().codegen_fn_attrs(item.owner_id);
-                        tcx.ensure().fn_sig(item.owner_id)
+                        tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
+                        tcx.ensure_ok().fn_sig(item.owner_id)
                     }
                     hir::ForeignItemKind::Static(..) => {
-                        tcx.ensure().codegen_fn_attrs(item.owner_id);
+                        tcx.ensure_ok().codegen_fn_attrs(item.owner_id);
                         let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_foreign_item(item);
                         placeholder_type_error(
@@ -713,40 +713,40 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             }
         }
         hir::ItemKind::Enum(..) => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().predicates_of(def_id);
+            tcx.ensure_ok().generics_of(def_id);
+            tcx.ensure_ok().type_of(def_id);
+            tcx.ensure_ok().predicates_of(def_id);
             lower_enum_variant_types(tcx, def_id.to_def_id());
         }
         hir::ItemKind::Impl { .. } => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().impl_trait_header(def_id);
-            tcx.ensure().predicates_of(def_id);
-            tcx.ensure().associated_items(def_id);
+            tcx.ensure_ok().generics_of(def_id);
+            tcx.ensure_ok().type_of(def_id);
+            tcx.ensure_ok().impl_trait_header(def_id);
+            tcx.ensure_ok().predicates_of(def_id);
+            tcx.ensure_ok().associated_items(def_id);
         }
         hir::ItemKind::Trait(..) => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().trait_def(def_id);
+            tcx.ensure_ok().generics_of(def_id);
+            tcx.ensure_ok().trait_def(def_id);
             tcx.at(it.span).explicit_super_predicates_of(def_id);
-            tcx.ensure().predicates_of(def_id);
-            tcx.ensure().associated_items(def_id);
+            tcx.ensure_ok().predicates_of(def_id);
+            tcx.ensure_ok().associated_items(def_id);
         }
         hir::ItemKind::TraitAlias(..) => {
-            tcx.ensure().generics_of(def_id);
+            tcx.ensure_ok().generics_of(def_id);
             tcx.at(it.span).explicit_implied_predicates_of(def_id);
             tcx.at(it.span).explicit_super_predicates_of(def_id);
-            tcx.ensure().predicates_of(def_id);
+            tcx.ensure_ok().predicates_of(def_id);
         }
         hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().predicates_of(def_id);
+            tcx.ensure_ok().generics_of(def_id);
+            tcx.ensure_ok().type_of(def_id);
+            tcx.ensure_ok().predicates_of(def_id);
 
             for f in struct_def.fields() {
-                tcx.ensure().generics_of(f.def_id);
-                tcx.ensure().type_of(f.def_id);
-                tcx.ensure().predicates_of(f.def_id);
+                tcx.ensure_ok().generics_of(f.def_id);
+                tcx.ensure_ok().type_of(f.def_id);
+                tcx.ensure_ok().predicates_of(f.def_id);
             }
 
             if let Some(ctor_def_id) = struct_def.ctor_def_id() {
@@ -755,15 +755,15 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
         }
 
         hir::ItemKind::TyAlias(..) => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().predicates_of(def_id);
+            tcx.ensure_ok().generics_of(def_id);
+            tcx.ensure_ok().type_of(def_id);
+            tcx.ensure_ok().predicates_of(def_id);
         }
 
         hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().predicates_of(def_id);
+            tcx.ensure_ok().generics_of(def_id);
+            tcx.ensure_ok().type_of(def_id);
+            tcx.ensure_ok().predicates_of(def_id);
             if !ty.is_suggestable_infer_ty() {
                 let mut visitor = HirPlaceholderCollector::default();
                 visitor.visit_item(it);
@@ -779,11 +779,11 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
         }
 
         hir::ItemKind::Fn { .. } => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().predicates_of(def_id);
-            tcx.ensure().fn_sig(def_id);
-            tcx.ensure().codegen_fn_attrs(def_id);
+            tcx.ensure_ok().generics_of(def_id);
+            tcx.ensure_ok().type_of(def_id);
+            tcx.ensure_ok().predicates_of(def_id);
+            tcx.ensure_ok().fn_sig(def_id);
+            tcx.ensure_ok().codegen_fn_attrs(def_id);
         }
     }
 }
@@ -791,18 +791,18 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
 fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
     let trait_item = tcx.hir().trait_item(trait_item_id);
     let def_id = trait_item_id.owner_id;
-    tcx.ensure().generics_of(def_id);
+    tcx.ensure_ok().generics_of(def_id);
     let icx = ItemCtxt::new(tcx, def_id.def_id);
 
     match trait_item.kind {
         hir::TraitItemKind::Fn(..) => {
-            tcx.ensure().codegen_fn_attrs(def_id);
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().fn_sig(def_id);
+            tcx.ensure_ok().codegen_fn_attrs(def_id);
+            tcx.ensure_ok().type_of(def_id);
+            tcx.ensure_ok().fn_sig(def_id);
         }
 
         hir::TraitItemKind::Const(ty, body_id) => {
-            tcx.ensure().type_of(def_id);
+            tcx.ensure_ok().type_of(def_id);
             if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
                 && !(ty.is_suggestable_infer_ty() && body_id.is_some())
             {
@@ -821,9 +821,9 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
         }
 
         hir::TraitItemKind::Type(_, Some(_)) => {
-            tcx.ensure().item_bounds(def_id);
-            tcx.ensure().item_self_bounds(def_id);
-            tcx.ensure().type_of(def_id);
+            tcx.ensure_ok().item_bounds(def_id);
+            tcx.ensure_ok().item_self_bounds(def_id);
+            tcx.ensure_ok().type_of(def_id);
             // Account for `type T = _;`.
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
@@ -838,8 +838,8 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
         }
 
         hir::TraitItemKind::Type(_, None) => {
-            tcx.ensure().item_bounds(def_id);
-            tcx.ensure().item_self_bounds(def_id);
+            tcx.ensure_ok().item_bounds(def_id);
+            tcx.ensure_ok().item_self_bounds(def_id);
             // #74612: Visit and try to find bad placeholders
             // even if there is no concrete type.
             let mut visitor = HirPlaceholderCollector::default();
@@ -856,20 +856,20 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
         }
     };
 
-    tcx.ensure().predicates_of(def_id);
+    tcx.ensure_ok().predicates_of(def_id);
 }
 
 fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
     let def_id = impl_item_id.owner_id;
-    tcx.ensure().generics_of(def_id);
-    tcx.ensure().type_of(def_id);
-    tcx.ensure().predicates_of(def_id);
+    tcx.ensure_ok().generics_of(def_id);
+    tcx.ensure_ok().type_of(def_id);
+    tcx.ensure_ok().predicates_of(def_id);
     let impl_item = tcx.hir().impl_item(impl_item_id);
     let icx = ItemCtxt::new(tcx, def_id.def_id);
     match impl_item.kind {
         hir::ImplItemKind::Fn(..) => {
-            tcx.ensure().codegen_fn_attrs(def_id);
-            tcx.ensure().fn_sig(def_id);
+            tcx.ensure_ok().codegen_fn_attrs(def_id);
+            tcx.ensure_ok().fn_sig(def_id);
         }
         hir::ImplItemKind::Type(_) => {
             // Account for `type T = _;`
@@ -904,9 +904,9 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
 }
 
 fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    tcx.ensure().generics_of(def_id);
-    tcx.ensure().type_of(def_id);
-    tcx.ensure().predicates_of(def_id);
+    tcx.ensure_ok().generics_of(def_id);
+    tcx.ensure_ok().type_of(def_id);
+    tcx.ensure_ok().predicates_of(def_id);
 }
 
 fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
@@ -937,9 +937,9 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
         );
 
         for f in &variant.fields {
-            tcx.ensure().generics_of(f.did);
-            tcx.ensure().type_of(f.did);
-            tcx.ensure().predicates_of(f.did);
+            tcx.ensure_ok().generics_of(f.did);
+            tcx.ensure_ok().type_of(f.did);
+            tcx.ensure_ok().predicates_of(f.did);
         }
 
         // Lower the ctor, if any. This also registers the variant as an item.
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index f1022d95753..4a508fc0cf6 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -1,7 +1,8 @@
+use rustc_hir as hir;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_hir::intravisit;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_span::sym;
 
 pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
@@ -87,3 +88,82 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
         }
     }
 }
+
+pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
+    for id in tcx.hir().items() {
+        let def_id = id.owner_id.def_id;
+
+        let Some(attr) = tcx.get_attr(def_id, sym::rustc_dump_vtable) else {
+            continue;
+        };
+
+        let vtable_entries = match tcx.hir().item(id).kind {
+            hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
+                let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity();
+                if trait_ref.has_non_region_param() {
+                    tcx.dcx().span_err(
+                        attr.span,
+                        "`rustc_dump_vtable` must be applied to non-generic impl",
+                    );
+                    continue;
+                }
+                if !tcx.is_dyn_compatible(trait_ref.def_id) {
+                    tcx.dcx().span_err(
+                        attr.span,
+                        "`rustc_dump_vtable` must be applied to dyn-compatible trait",
+                    );
+                    continue;
+                }
+                let Ok(trait_ref) = tcx
+                    .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref)
+                else {
+                    tcx.dcx().span_err(
+                        attr.span,
+                        "`rustc_dump_vtable` applied to impl header that cannot be normalized",
+                    );
+                    continue;
+                };
+                tcx.vtable_entries(trait_ref)
+            }
+            hir::ItemKind::TyAlias(_, _) => {
+                let ty = tcx.type_of(def_id).instantiate_identity();
+                if ty.has_non_region_param() {
+                    tcx.dcx().span_err(
+                        attr.span,
+                        "`rustc_dump_vtable` must be applied to non-generic type",
+                    );
+                    continue;
+                }
+                let Ok(ty) =
+                    tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
+                else {
+                    tcx.dcx().span_err(
+                        attr.span,
+                        "`rustc_dump_vtable` applied to type alias that cannot be normalized",
+                    );
+                    continue;
+                };
+                let ty::Dynamic(data, _, _) = *ty.kind() else {
+                    tcx.dcx().span_err(attr.span, "`rustc_dump_vtable` to type alias of dyn type");
+                    continue;
+                };
+                if let Some(principal) = data.principal() {
+                    tcx.vtable_entries(
+                        tcx.instantiate_bound_regions_with_erased(principal).with_self_ty(tcx, ty),
+                    )
+                } else {
+                    TyCtxt::COMMON_VTABLE_ENTRIES
+                }
+            }
+            _ => {
+                tcx.dcx().span_err(
+                    attr.span,
+                    "`rustc_dump_vtable` only applies to impl, or type alias of dyn type",
+                );
+                continue;
+            }
+        };
+
+        tcx.dcx().span_err(tcx.def_span(def_id), format!("vtable entries: {vtable_entries:#?}"));
+    }
+}
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 72baf5c4b58..d67b9d33596 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -12,13 +12,11 @@ use std::ops::ControlFlow;
 
 use rustc_ast::visit::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
 use rustc_hir::{
-    self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap,
-    LifetimeName, Node,
+    self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeName, Node,
 };
 use rustc_macros::extension;
 use rustc_middle::hir::nested_filter;
@@ -26,7 +24,7 @@ use rustc_middle::middle::resolve_bound_vars::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_middle::{bug, span_bug};
-use rustc_span::def_id::{DefId, LocalDefId, LocalDefIdMap};
+use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::{Ident, Span, sym};
 use tracing::{debug, debug_span, instrument};
 
@@ -62,33 +60,9 @@ impl ResolvedArg {
     }
 }
 
-/// Maps the id of each bound variable reference to the variable decl
-/// that it corresponds to.
-///
-/// FIXME. This struct gets converted to a `ResolveBoundVars` for
-/// actual use. It has the same data, but indexed by `LocalDefId`. This
-/// is silly.
-#[derive(Debug, Default)]
-struct NamedVarMap {
-    // maps from every use of a named (not anonymous) bound var to a
-    // `ResolvedArg` describing how that variable is bound
-    defs: ItemLocalMap<ResolvedArg>,
-
-    // Maps relevant hir items to the bound vars on them. These include:
-    // - function defs
-    // - function pointers
-    // - closures
-    // - trait refs
-    // - bound types (like `T` in `for<'a> T<'a>: Foo`)
-    late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>,
-
-    // List captured variables for each opaque type.
-    opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>,
-}
-
 struct BoundVarContext<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    map: &'a mut NamedVarMap,
+    rbv: &'a mut ResolveBoundVars,
     scope: ScopeRef<'a>,
 }
 
@@ -267,19 +241,12 @@ pub(crate) fn provide(providers: &mut Providers) {
 
 /// Computes the `ResolveBoundVars` map that contains data for an entire `Item`.
 /// You should not read the result of this query directly, but rather use
-/// `named_variable_map`, `is_late_bound_map`, etc.
+/// `named_variable_map`, `late_bound_vars_map`, etc.
 #[instrument(level = "debug", skip(tcx))]
 fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
-    let mut named_variable_map = NamedVarMap {
-        defs: Default::default(),
-        late_bound_vars: Default::default(),
-        opaque_captured_lifetimes: Default::default(),
-    };
-    let mut visitor = BoundVarContext {
-        tcx,
-        map: &mut named_variable_map,
-        scope: &Scope::Root { opt_parent_item: None },
-    };
+    let mut rbv = ResolveBoundVars::default();
+    let mut visitor =
+        BoundVarContext { tcx, rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None } };
     match tcx.hir_owner_node(local_def_id) {
         hir::OwnerNode::Item(item) => visitor.visit_item(item),
         hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
@@ -299,19 +266,10 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
         hir::OwnerNode::Synthetic => unreachable!(),
     }
 
-    let defs = named_variable_map.defs.into_sorted_stable_ord();
-    let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord();
-    let opaque_captured_lifetimes = named_variable_map.opaque_captured_lifetimes;
-    let rl = ResolveBoundVars {
-        defs: SortedMap::from_presorted_elements(defs),
-        late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars),
-        opaque_captured_lifetimes,
-    };
-
-    debug!(?rl.defs);
-    debug!(?rl.late_bound_vars);
-    debug!(?rl.opaque_captured_lifetimes);
-    rl
+    debug!(?rbv.defs);
+    debug!(?rbv.late_bound_vars);
+    debug!(?rbv.opaque_captured_lifetimes);
+    rbv
 }
 
 fn late_arg_as_bound_arg<'tcx>(
@@ -404,7 +362,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 Scope::Binder { hir_id, .. } => {
                     // Nested poly trait refs have the binders concatenated
                     let mut full_binders =
-                        self.map.late_bound_vars.entry(hir_id.local_id).or_default().clone();
+                        self.rbv.late_bound_vars.get_mut_or_insert_default(hir_id.local_id).clone();
                     full_binders.extend(supertrait_bound_vars);
                     break (full_binders, BinderScopeType::Concatenating);
                 }
@@ -646,7 +604,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
 
         let captures = captures.into_inner().into_iter().collect();
         debug!(?captures);
-        self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures);
+        self.rbv.opaque_captured_lifetimes.insert(opaque.def_id, captures);
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -848,7 +806,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             hir::TyKind::Ref(lifetime_ref, ref mt) => {
                 self.visit_lifetime(lifetime_ref);
                 let scope = Scope::ObjectLifetimeDefault {
-                    lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
+                    lifetime: self.rbv.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
                     s: self.scope,
                 };
                 self.with(scope, |this| this.visit_ty_unambig(mt.ty));
@@ -966,7 +924,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             let bound_vars: Vec<_> =
                 self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect();
             let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
-            self.map.late_bound_vars.insert(hir_id.local_id, bound_vars);
+            self.rbv.late_bound_vars.insert(hir_id.local_id, bound_vars);
         }
         self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
         intravisit::walk_fn_kind(self, fk);
@@ -1140,8 +1098,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     where
         F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
     {
-        let BoundVarContext { tcx, map, .. } = self;
-        let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope };
+        let BoundVarContext { tcx, rbv, .. } = self;
+        let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope };
         let span = debug_span!("scope", scope = ?this.scope.debug_truncated());
         {
             let _enter = span.enter();
@@ -1150,10 +1108,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     }
 
     fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind>) {
-        if let Some(old) = self.map.late_bound_vars.insert(hir_id.local_id, binder) {
+        if let Some(old) = self.rbv.late_bound_vars.insert(hir_id.local_id, binder) {
             bug!(
                 "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
-                self.map.late_bound_vars[&hir_id.local_id]
+                self.rbv.late_bound_vars[&hir_id.local_id]
             )
         }
     }
@@ -1597,9 +1555,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         kind.descr(param_def_id.to_def_id())
                     ),
                 };
-                self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
+                self.rbv.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
             } else {
-                self.map.defs.insert(hir_id.local_id, def);
+                self.rbv.defs.insert(hir_id.local_id, def);
             }
             return;
         }
@@ -1632,7 +1590,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                             bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id()))
                         }
                     });
-                    self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
+                    self.rbv.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
                     return;
                 }
                 Scope::Root { .. } => break,
@@ -1725,7 +1683,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 }
             };
 
-            let map = &self.map;
+            let rbv = &self.rbv;
             let generics = self.tcx.generics_of(def_id);
 
             // `type_def_id` points to an item, so there is nothing to inherit generics from.
@@ -1744,7 +1702,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     // This index can be used with `generic_args` since `parent_count == 0`.
                     let index = generics.param_def_id_to_index[&param_def_id] as usize;
                     generic_args.args.get(index).and_then(|arg| match arg {
-                        GenericArg::Lifetime(lt) => map.defs.get(&lt.hir_id.local_id).copied(),
+                        GenericArg::Lifetime(lt) => rbv.defs.get(&lt.hir_id.local_id).copied(),
                         _ => None,
                     })
                 }
@@ -2042,7 +2000,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) {
         debug!(span = ?lifetime_ref.ident.span);
-        self.map.defs.insert(lifetime_ref.hir_id.local_id, def);
+        self.rbv.defs.insert(lifetime_ref.hir_id.local_id, def);
     }
 
     // When we have a return type notation type in a where clause, like
@@ -2197,7 +2155,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`.
         // And this is exercised in:
         // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`.
-        let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id.local_id).unwrap();
+        let existing_bound_vars = self.rbv.late_bound_vars.get_mut(&hir_id.local_id).unwrap();
         let existing_bound_vars_saved = existing_bound_vars.clone();
         existing_bound_vars.extend(bound_vars);
         self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index e65420ea8bf..ed45833b614 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -100,213 +100,156 @@ enum InheritanceKind {
     Own,
 }
 
-struct GenericsBuilder<'tcx> {
+fn build_generics<'tcx>(
     tcx: TyCtxt<'tcx>,
     sig_id: DefId,
     parent: Option<DefId>,
     inh_kind: InheritanceKind,
-}
-
-impl<'tcx> GenericsBuilder<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, sig_id: DefId) -> GenericsBuilder<'tcx> {
-        GenericsBuilder { tcx, sig_id, parent: None, inh_kind: InheritanceKind::WithParent(false) }
-    }
-
-    fn with_parent(mut self, parent: DefId) -> Self {
-        self.parent = Some(parent);
-        self
-    }
-
-    fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self {
-        self.inh_kind = inh_kind;
-        self
-    }
-
-    fn build(self) -> ty::Generics {
-        let mut own_params = vec![];
+) -> ty::Generics {
+    let mut own_params = vec![];
 
-        let sig_generics = self.tcx.generics_of(self.sig_id);
-        if let InheritanceKind::WithParent(has_self) = self.inh_kind
-            && let Some(parent_def_id) = sig_generics.parent
-        {
-            let sig_parent_generics = self.tcx.generics_of(parent_def_id);
-            own_params.append(&mut sig_parent_generics.own_params.clone());
-            if !has_self {
-                own_params.remove(0);
-            }
+    let sig_generics = tcx.generics_of(sig_id);
+    if let InheritanceKind::WithParent(has_self) = inh_kind
+        && let Some(parent_def_id) = sig_generics.parent
+    {
+        let sig_parent_generics = tcx.generics_of(parent_def_id);
+        own_params.append(&mut sig_parent_generics.own_params.clone());
+        if !has_self {
+            own_params.remove(0);
         }
-        own_params.append(&mut sig_generics.own_params.clone());
+    }
+    own_params.append(&mut sig_generics.own_params.clone());
+
+    // Lifetime parameters must be declared before type and const parameters.
+    // Therefore, When delegating from a free function to a associated function,
+    // generic parameters need to be reordered:
+    //
+    // trait Trait<'a, A> {
+    //     fn foo<'b, B>(...) {...}
+    // }
+    //
+    // reuse Trait::foo;
+    // desugaring:
+    // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
+    //     Trait::foo(...)
+    // }
+    own_params.sort_by_key(|key| key.kind.is_ty_or_const());
+
+    let param_def_id_to_index =
+        own_params.iter().map(|param| (param.def_id, param.index)).collect();
+
+    let (parent_count, has_self) = if let Some(def_id) = parent {
+        let parent_generics = tcx.generics_of(def_id);
+        let parent_kind = tcx.def_kind(def_id);
+        (parent_generics.count(), parent_kind == DefKind::Trait)
+    } else {
+        (0, false)
+    };
 
-        // Lifetime parameters must be declared before type and const parameters.
-        // Therefore, When delegating from a free function to a associated function,
-        // generic parameters need to be reordered:
+    for (idx, param) in own_params.iter_mut().enumerate() {
+        param.index = (idx + parent_count) as u32;
+        // FIXME(fn_delegation): Default parameters are not inherited, because they are
+        // not permitted in functions. Therefore, there are 2 options here:
         //
-        // trait Trait<'a, A> {
-        //     fn foo<'b, B>(...) {...}
-        // }
+        // - We can create non-default generic parameters.
+        // - We can substitute default parameters into the signature.
         //
-        // reuse Trait::foo;
-        // desugaring:
-        // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
-        //     Trait::foo(...)
-        // }
-        own_params.sort_by_key(|key| key.kind.is_ty_or_const());
-
-        let param_def_id_to_index =
-            own_params.iter().map(|param| (param.def_id, param.index)).collect();
-
-        let (parent_count, has_self) = if let Some(def_id) = self.parent {
-            let parent_generics = self.tcx.generics_of(def_id);
-            let parent_kind = self.tcx.def_kind(def_id);
-            (parent_generics.count(), parent_kind == DefKind::Trait)
-        } else {
-            (0, false)
-        };
-
-        for (idx, param) in own_params.iter_mut().enumerate() {
-            param.index = (idx + parent_count) as u32;
-            // FIXME(fn_delegation): Default parameters are not inherited, because they are
-            // not permitted in functions. Therefore, there are 2 options here:
-            //
-            // - We can create non-default generic parameters.
-            // - We can substitute default parameters into the signature.
-            //
-            // At the moment, first option has been selected as the most general.
-            if let ty::GenericParamDefKind::Type { has_default, .. }
-            | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
-            {
-                *has_default = false;
-            }
+        // At the moment, first option has been selected as the most general.
+        if let ty::GenericParamDefKind::Type { has_default, .. }
+        | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
+        {
+            *has_default = false;
         }
+    }
 
-        ty::Generics {
-            parent: self.parent,
-            parent_count,
-            own_params,
-            param_def_id_to_index,
-            has_self,
-            has_late_bound_regions: sig_generics.has_late_bound_regions,
-        }
+    ty::Generics {
+        parent,
+        parent_count,
+        own_params,
+        param_def_id_to_index,
+        has_self,
+        has_late_bound_regions: sig_generics.has_late_bound_regions,
     }
 }
 
-struct PredicatesBuilder<'tcx> {
+fn build_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     sig_id: DefId,
     parent: Option<DefId>,
     inh_kind: InheritanceKind,
     args: ty::GenericArgsRef<'tcx>,
-}
-
-impl<'tcx> PredicatesBuilder<'tcx> {
-    fn new(
+) -> ty::GenericPredicates<'tcx> {
+    struct PredicatesCollector<'tcx> {
         tcx: TyCtxt<'tcx>,
+        preds: Vec<(ty::Clause<'tcx>, Span)>,
         args: ty::GenericArgsRef<'tcx>,
-        sig_id: DefId,
-    ) -> PredicatesBuilder<'tcx> {
-        PredicatesBuilder {
-            tcx,
-            sig_id,
-            parent: None,
-            inh_kind: InheritanceKind::WithParent(false),
-            args,
-        }
-    }
-
-    fn with_parent(mut self, parent: DefId) -> Self {
-        self.parent = Some(parent);
-        self
     }
 
-    fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self {
-        self.inh_kind = inh_kind;
-        self
-    }
-
-    fn build(self) -> ty::GenericPredicates<'tcx> {
-        struct PredicatesCollector<'tcx> {
-            tcx: TyCtxt<'tcx>,
-            preds: Vec<(ty::Clause<'tcx>, Span)>,
-            args: ty::GenericArgsRef<'tcx>,
+    impl<'tcx> PredicatesCollector<'tcx> {
+        fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> {
+            PredicatesCollector { tcx, preds: vec![], args }
         }
 
-        impl<'tcx> PredicatesCollector<'tcx> {
-            fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> {
-                PredicatesCollector { tcx, preds: vec![], args }
-            }
-
-            fn with_own_preds(
-                mut self,
-                f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>,
-                def_id: DefId,
-            ) -> Self {
-                let preds = f(def_id).instantiate_own(self.tcx, self.args);
-                self.preds.extend(preds);
-                self
-            }
+        fn with_own_preds(
+            mut self,
+            f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>,
+            def_id: DefId,
+        ) -> Self {
+            let preds = f(def_id).instantiate_own(self.tcx, self.args);
+            self.preds.extend(preds);
+            self
+        }
 
-            fn with_preds(
-                mut self,
-                f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy,
-                def_id: DefId,
-            ) -> Self {
-                let preds = f(def_id);
-                if let Some(parent_def_id) = preds.parent {
-                    self = self.with_own_preds(f, parent_def_id);
-                }
-                self.with_own_preds(f, def_id)
+        fn with_preds(
+            mut self,
+            f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy,
+            def_id: DefId,
+        ) -> Self {
+            let preds = f(def_id);
+            if let Some(parent_def_id) = preds.parent {
+                self = self.with_own_preds(f, parent_def_id);
             }
+            self.with_own_preds(f, def_id)
         }
-        let collector = PredicatesCollector::new(self.tcx, self.args);
-
-        // `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate.
-        // Note: `predicates_of` query can also add inferred outlives predicates, but that
-        // is not the case here as `sig_id` is either a trait or a function.
-        let preds = match self.inh_kind {
-            InheritanceKind::WithParent(false) => {
-                collector.with_preds(|def_id| self.tcx.explicit_predicates_of(def_id), self.sig_id)
-            }
-            InheritanceKind::WithParent(true) => {
-                collector.with_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id)
-            }
-            InheritanceKind::Own => {
-                collector.with_own_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id)
-            }
+    }
+    let collector = PredicatesCollector::new(tcx, args);
+
+    // `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate.
+    // Note: `predicates_of` query can also add inferred outlives predicates, but that
+    // is not the case here as `sig_id` is either a trait or a function.
+    let preds = match inh_kind {
+        InheritanceKind::WithParent(false) => {
+            collector.with_preds(|def_id| tcx.explicit_predicates_of(def_id), sig_id)
         }
-        .preds;
-
-        ty::GenericPredicates {
-            parent: self.parent,
-            predicates: self.tcx.arena.alloc_from_iter(preds),
+        InheritanceKind::WithParent(true) => {
+            collector.with_preds(|def_id| tcx.predicates_of(def_id), sig_id)
+        }
+        InheritanceKind::Own => {
+            collector.with_own_preds(|def_id| tcx.predicates_of(def_id), sig_id)
         }
     }
+    .preds;
+
+    ty::GenericPredicates { parent, predicates: tcx.arena.alloc_from_iter(preds) }
 }
 
-struct GenericArgsBuilder<'tcx> {
+fn build_generic_args<'tcx>(
     tcx: TyCtxt<'tcx>,
-    remap_table: RemapTable,
     sig_id: DefId,
     def_id: LocalDefId,
-}
+    args: ty::GenericArgsRef<'tcx>,
+) -> ty::GenericArgsRef<'tcx> {
+    let caller_generics = tcx.generics_of(def_id);
+    let callee_generics = tcx.generics_of(sig_id);
 
-impl<'tcx> GenericArgsBuilder<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId) -> GenericArgsBuilder<'tcx> {
-        GenericArgsBuilder { tcx, remap_table: FxHashMap::default(), sig_id, def_id }
+    let mut remap_table = FxHashMap::default();
+    for caller_param in &caller_generics.own_params {
+        let callee_index = callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap();
+        remap_table.insert(callee_index, caller_param.index);
     }
 
-    fn build_from_args(mut self, args: ty::GenericArgsRef<'tcx>) -> ty::GenericArgsRef<'tcx> {
-        let caller_generics = self.tcx.generics_of(self.def_id);
-        let callee_generics = self.tcx.generics_of(self.sig_id);
-
-        for caller_param in &caller_generics.own_params {
-            let callee_index =
-                callee_generics.param_def_id_to_index(self.tcx, caller_param.def_id).unwrap();
-            self.remap_table.insert(callee_index, caller_param.index);
-        }
-
-        let mut folder = ParamIndexRemapper { tcx: self.tcx, remap_table: self.remap_table };
-        args.fold_with(&mut folder)
-    }
+    let mut folder = ParamIndexRemapper { tcx, remap_table };
+    args.fold_with(&mut folder)
 }
 
 fn create_generic_args<'tcx>(
@@ -314,8 +257,6 @@ fn create_generic_args<'tcx>(
     def_id: LocalDefId,
     sig_id: DefId,
 ) -> ty::GenericArgsRef<'tcx> {
-    let builder = GenericArgsBuilder::new(tcx, sig_id, def_id);
-
     let caller_kind = fn_kind(tcx, def_id.into());
     let callee_kind = fn_kind(tcx, sig_id);
     match (caller_kind, callee_kind) {
@@ -325,7 +266,7 @@ fn create_generic_args<'tcx>(
         | (FnKind::AssocTrait, FnKind::Free)
         | (FnKind::AssocTrait, FnKind::AssocTrait) => {
             let args = ty::GenericArgs::identity_for_item(tcx, sig_id);
-            builder.build_from_args(args)
+            build_generic_args(tcx, sig_id, def_id, args)
         }
 
         (FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
@@ -335,8 +276,9 @@ fn create_generic_args<'tcx>(
                 tcx.impl_trait_header(parent).unwrap().trait_ref.instantiate_identity().args;
 
             let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id);
-            let method_args = tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count));
-            let method_args = builder.build_from_args(method_args);
+            let method_args =
+                tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count));
+            let method_args = build_generic_args(tcx, sig_id, def_id, method_args);
 
             tcx.mk_args_from_iter(parent_args.iter().chain(method_args))
         }
@@ -347,16 +289,16 @@ fn create_generic_args<'tcx>(
             let generic_self_ty = ty::GenericArg::from(self_ty);
 
             let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id);
-            let trait_args = builder.build_from_args(trait_args);
+            let trait_args = build_generic_args(tcx, sig_id, def_id, trait_args);
 
             let args = std::iter::once(generic_self_ty).chain(trait_args.iter().skip(1));
             tcx.mk_args_from_iter(args)
         }
 
         // For trait impl's `sig_id` is always equal to the corresponding trait method.
+        // For inherent methods delegation is not yet supported.
         (FnKind::AssocTraitImpl, _)
         | (_, FnKind::AssocTraitImpl)
-        // Delegation to inherent methods is not yet supported.
         | (_, FnKind::AssocInherentImpl) => unreachable!(),
     }
 }
@@ -377,39 +319,31 @@ pub(crate) fn inherit_generics_for_delegation_item<'tcx>(
     def_id: LocalDefId,
     sig_id: DefId,
 ) -> ty::Generics {
-    let builder = GenericsBuilder::new(tcx, sig_id);
-
     let caller_kind = fn_kind(tcx, def_id.into());
     let callee_kind = fn_kind(tcx, sig_id);
     match (caller_kind, callee_kind) {
-        (FnKind::Free, FnKind::Free)
-        | (FnKind::Free, FnKind::AssocTrait) => builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build(),
+        (FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) => {
+            build_generics(tcx, sig_id, None, InheritanceKind::WithParent(true))
+        }
 
         (FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
-            builder
-            .with_parent(tcx.parent(def_id.into()))
-            .with_inheritance_kind(InheritanceKind::Own)
-            .build()
+            build_generics(tcx, sig_id, Some(tcx.parent(def_id.into())), InheritanceKind::Own)
         }
 
         (FnKind::AssocInherentImpl, FnKind::AssocTrait)
-        | (FnKind::AssocTrait, FnKind::AssocTrait) => {
-            builder
-            .with_parent(tcx.parent(def_id.into()))
-            .build()
-        }
-
-        (FnKind::AssocInherentImpl, FnKind::Free)
-        | (FnKind::AssocTrait, FnKind::Free) => {
-            builder
-            .with_parent(tcx.parent(def_id.into()))
-            .build()
-        }
+        | (FnKind::AssocTrait, FnKind::AssocTrait)
+        | (FnKind::AssocInherentImpl, FnKind::Free)
+        | (FnKind::AssocTrait, FnKind::Free) => build_generics(
+            tcx,
+            sig_id,
+            Some(tcx.parent(def_id.into())),
+            InheritanceKind::WithParent(false),
+        ),
 
         // For trait impl's `sig_id` is always equal to the corresponding trait method.
+        // For inherent methods delegation is not yet supported.
         (FnKind::AssocTraitImpl, _)
         | (_, FnKind::AssocTraitImpl)
-        // Delegation to inherent methods is not yet supported.
         | (_, FnKind::AssocInherentImpl) => unreachable!(),
     }
 }
@@ -420,36 +354,36 @@ pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(
     sig_id: DefId,
 ) -> ty::GenericPredicates<'tcx> {
     let args = create_generic_args(tcx, def_id, sig_id);
-    let builder = PredicatesBuilder::new(tcx, args, sig_id);
-
     let caller_kind = fn_kind(tcx, def_id.into());
     let callee_kind = fn_kind(tcx, sig_id);
     match (caller_kind, callee_kind) {
-        (FnKind::Free, FnKind::Free)
-        | (FnKind::Free, FnKind::AssocTrait) => {
-            builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build()
+        (FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) => {
+            build_predicates(tcx, sig_id, None, InheritanceKind::WithParent(true), args)
         }
 
-        (FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
-            builder
-            .with_parent(tcx.parent(def_id.into()))
-            .with_inheritance_kind(InheritanceKind::Own)
-            .build()
-        }
+        (FnKind::AssocTraitImpl, FnKind::AssocTrait) => build_predicates(
+            tcx,
+            sig_id,
+            Some(tcx.parent(def_id.into())),
+            InheritanceKind::Own,
+            args,
+        ),
 
         (FnKind::AssocInherentImpl, FnKind::AssocTrait)
         | (FnKind::AssocTrait, FnKind::AssocTrait)
         | (FnKind::AssocInherentImpl, FnKind::Free)
-        | (FnKind::AssocTrait, FnKind::Free) => {
-            builder
-                .with_parent(tcx.parent(def_id.into()))
-                .build()
-        }
+        | (FnKind::AssocTrait, FnKind::Free) => build_predicates(
+            tcx,
+            sig_id,
+            Some(tcx.parent(def_id.into())),
+            InheritanceKind::WithParent(false),
+            args,
+        ),
 
         // For trait impl's `sig_id` is always equal to the corresponding trait method.
+        // For inherent methods delegation is not yet supported.
         (FnKind::AssocTraitImpl, _)
         | (_, FnKind::AssocTraitImpl)
-        // Delegation to inherent methods is not yet supported.
         | (_, FnKind::AssocInherentImpl) => unreachable!(),
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs
index bb771d6ea17..272edbe841b 100644
--- a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs
+++ b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs
@@ -1,4 +1,5 @@
 use rustc_macros::Diagnostic;
+use rustc_middle::ty::Ty;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
@@ -7,3 +8,14 @@ pub(crate) struct WildPatTy {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_invalid_base_type)]
+pub(crate) struct InvalidBaseType<'tcx> {
+    pub ty: Ty<'tcx>,
+    #[primary_span]
+    pub ty_span: Span,
+    pub pat: &'static str,
+    #[note]
+    pub pat_span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index 67407349729..b2501d647a5 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -495,6 +495,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
                         .iter()
                         .any(|constraint| constraint.ident.name == item.name)
                 })
+                .filter(|item| !item.is_impl_trait_in_trait())
                 .map(|item| self.tcx.item_ident(item.def_id).to_string())
                 .collect()
         } else {
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 36b214b6ae7..79aa2f4b8cc 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::codes::*;
 use rustc_errors::{
-    Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err,
+    Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -808,14 +808,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .map(|(trait_, mut assocs)| {
                 assocs.sort();
                 let trait_ = trait_.print_trait_sugared();
-                format!("{} in `{trait_}`", match &assocs[..] {
-                    [] => String::new(),
-                    [only] => format!("`{only}`"),
-                    [assocs @ .., last] => format!(
-                        "{} and `{last}`",
-                        assocs.iter().map(|a| format!("`{a}`")).collect::<Vec<_>>().join(", ")
-                    ),
-                })
+                format!(
+                    "{} in `{trait_}`",
+                    listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
+                )
             })
             .collect::<Vec<String>>();
         names.sort();
@@ -1075,18 +1071,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 }
             })
             .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(),
-            [] => bug!("expected one segment to deny"),
-        };
+        let this_type = listify(&types_and_spans, |(t, _)| t.to_string())
+            .expect("expected one segment to deny");
 
         let arg_spans: Vec<Span> = segments
             .clone()
@@ -1102,21 +1088,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             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(), ""),
-            [] => bug!("expected at least one generic to prohibit"),
-        };
+        let s = pluralize!(kinds.len());
+        let kind =
+            listify(&kinds, |k| k.to_string()).expect("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!(
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index fe3dcb35639..43137397870 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -273,7 +273,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
 
                             // We lower to an infer even when the feature gate is not enabled
                             // as it is useful for diagnostics to be able to see a `ConstKind::Infer`
-                            args.push(ctx.provided_kind(&args, param, arg));
+                            args.push(ctx.provided_kind(param, arg));
                             args_iter.next();
                             params.next();
                         }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 539c5f6a20a..44f7a035a10 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -41,8 +41,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
                 ..
             })
-            | hir::Node::Pat(hir::Pat {
-                kind: hir::PatKind::Path(hir::QPath::TypeRelative(qself, _)),
+            | hir::Node::PatExpr(hir::PatExpr {
+                kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
                 ..
             }) if qself.hir_id == self_ty.hir_id => true,
             _ => false,
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 61d5869c19f..5813fdeae76 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -53,7 +53,7 @@ use tracing::{debug, instrument};
 
 use crate::bounds::Bounds;
 use crate::check::check_abi_fn_ptr;
-use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy};
+use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, WildPatTy};
 use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
@@ -296,7 +296,6 @@ pub trait GenericArgsLowerer<'a, 'tcx> {
 
     fn provided_kind(
         &mut self,
-        preceding_args: &[ty::GenericArg<'tcx>],
         param: &ty::GenericParamDef,
         arg: &GenericArg<'tcx>,
     ) -> ty::GenericArg<'tcx>;
@@ -480,7 +479,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             fn provided_kind(
                 &mut self,
-                _preceding_args: &[ty::GenericArg<'tcx>],
                 param: &ty::GenericParamDef,
                 arg: &GenericArg<'tcx>,
             ) -> ty::GenericArg<'tcx> {
@@ -2434,6 +2432,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 self.ty_infer(None, hir_ty.span)
             }
             hir::TyKind::Pat(ty, pat) => {
+                let ty_span = ty.span;
                 let ty = self.lower_ty(ty);
                 let pat_ty = match pat.kind {
                     hir::PatKind::Wild => {
@@ -2441,6 +2440,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         Ty::new_error(tcx, err)
                     }
                     hir::PatKind::Range(start, end, include_end) => {
+                        let ty = match ty.kind() {
+                            ty::Int(_) | ty::Uint(_) | ty::Char => ty,
+                            _ => Ty::new_error(
+                                tcx,
+                                self.dcx().emit_err(InvalidBaseType {
+                                    ty,
+                                    pat: "range",
+                                    ty_span,
+                                    pat_span: pat.span,
+                                }),
+                            ),
+                        };
                         let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
                             let (c, c_ty) = match expr.kind {
                                 hir::PatExprKind::Lit { lit, negated } => {
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index fd5a7089b4c..c30b39dfe76 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -62,7 +62,7 @@ pub(crate) fn check_impl_wf(
     // Check that the args are constrained. We queryfied the check for ty/const params
     // since unconstrained type/const params cause ICEs in projection, so we want to
     // detect those specifically and project those to `TyKind::Error`.
-    let mut res = tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
+    let mut res = tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
     res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id));
 
     if tcx.features().min_specialization() {
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index ee55e1bc21a..af1107b499f 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -34,7 +34,7 @@
 //! impl<T, I: Iterator<Item=T>> SpecExtend<T> for I { /* default impl */ }
 //! ```
 //!
-//! We get that the generic pamameters for `impl2` are `[T, std::vec::IntoIter<T>]`.
+//! We get that the generic parameters for `impl2` are `[T, std::vec::IntoIter<T>]`.
 //! `T` is constrained to be `<I as Iterator>::Item`, so we check only
 //! `std::vec::IntoIter<T>` for repeated parameters, which it doesn't have. The
 //! predicates of `impl1` are only `T: Sized`, which is also a predicate of
@@ -68,7 +68,6 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
@@ -77,7 +76,6 @@ use rustc_middle::ty::{
 };
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
-use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCtxt, translate_args_with_cause, wf};
 use tracing::{debug, instrument};
 
@@ -121,7 +119,6 @@ fn check_always_applicable(
     impl2_node: Node,
 ) -> Result<(), ErrorGuaranteed> {
     let span = tcx.def_span(impl1_def_id);
-    let mut res = check_has_items(tcx, impl1_def_id, impl2_node, span);
 
     let (impl1_args, impl2_args) = get_impl_args(tcx, impl1_def_id, impl2_node)?;
     let impl2_def_id = impl2_node.def_id();
@@ -133,11 +130,10 @@ fn check_always_applicable(
         unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args)
     };
 
-    res = res.and(check_static_lifetimes(tcx, &parent_args, span));
-    res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span));
-    res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span));
-
-    res
+    check_has_items(tcx, impl1_def_id, impl2_node, span)
+        .and(check_static_lifetimes(tcx, &parent_args, span))
+        .and(check_duplicate_params(tcx, impl1_args, parent_args, span))
+        .and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span))
 }
 
 fn check_has_items(
@@ -176,7 +172,6 @@ fn get_impl_args(
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
     let param_env = tcx.param_env(impl1_def_id);
     let impl1_span = tcx.def_span(impl1_def_id);
-    let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?;
 
     let impl1_args = GenericArgs::identity_for_item(tcx, impl1_def_id);
     let impl2_args = translate_args_with_cause(
@@ -194,9 +189,8 @@ fn get_impl_args(
         return Err(guar);
     }
 
-    let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, &assumed_wf_types);
-    let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
-    let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
+    let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?;
+    let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, param_env, assumed_wf_types);
     let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
         let span = tcx.def_span(impl1_def_id);
         let guar = tcx.dcx().emit_err(GenericArgsOnOverriddenImpl { span });
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index bc7d4365eee..3af4318544e 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -83,12 +83,11 @@ pub mod autoderef;
 mod bounds;
 mod check_unused;
 mod coherence;
-mod delegation;
-pub mod hir_ty_lowering;
-// FIXME: This module shouldn't be public.
-pub mod collect;
+mod collect;
 mod constrained_generic_params;
+mod delegation;
 mod errors;
+pub mod hir_ty_lowering;
 pub mod hir_wf_check;
 mod impl_wf_check;
 mod outlives;
@@ -101,10 +100,11 @@ use rustc_middle::middle;
 use rustc_middle::mir::interpret::GlobalId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Const, Ty, TyCtxt};
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits;
 
-use self::hir_ty_lowering::{FeedConstTy, HirTyLowerer};
+pub use crate::collect::suggest_impl_trait;
+use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer};
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
@@ -139,24 +139,31 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     let _prof_timer = tcx.sess.timer("type_check_crate");
 
     tcx.sess.time("coherence_checking", || {
+        // When discarding query call results, use an explicit type to indicate
+        // what we are intending to discard, to help future type-based refactoring.
+        type R = Result<(), ErrorGuaranteed>;
+
         tcx.hir().par_for_each_module(|module| {
-            let _ = tcx.ensure().check_mod_type_wf(module);
+            let _: R = tcx.ensure_ok().check_mod_type_wf(module);
         });
 
         for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
-            let _ = tcx.ensure().coherent_trait(trait_def_id);
+            let _: R = tcx.ensure_ok().coherent_trait(trait_def_id);
         }
         // these queries are executed for side-effects (error reporting):
-        let _ = tcx.ensure().crate_inherent_impls_validity_check(());
-        let _ = tcx.ensure().crate_inherent_impls_overlap_check(());
+        let _: R = tcx.ensure_ok().crate_inherent_impls_validity_check(());
+        let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(());
     });
 
     if tcx.features().rustc_attrs() {
-        tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx));
-        tcx.sess.time("variance_dumping", || variance::dump::variances(tcx));
-        collect::dump::opaque_hidden_types(tcx);
-        collect::dump::predicates_and_item_bounds(tcx);
-        collect::dump::def_parents(tcx);
+        tcx.sess.time("dumping_rustc_attr_data", || {
+            outlives::dump::inferred_outlives(tcx);
+            variance::dump::variances(tcx);
+            collect::dump::opaque_hidden_types(tcx);
+            collect::dump::predicates_and_item_bounds(tcx);
+            collect::dump::def_parents(tcx);
+            collect::dump::vtables(tcx);
+        });
     }
 
     // Make sure we evaluate all static and (non-associated) const items, even if unused.
@@ -164,12 +171,12 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     tcx.hir().par_body_owners(|item_def_id| {
         let def_kind = tcx.def_kind(item_def_id);
         match def_kind {
-            DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id),
+            DefKind::Static { .. } => tcx.ensure_ok().eval_static_initializer(item_def_id),
             DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
                 let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty());
                 let cid = GlobalId { instance, promoted: None };
                 let typing_env = ty::TypingEnv::fully_monomorphized();
-                tcx.ensure().eval_to_const_value_raw(typing_env.as_query_input(cid));
+                tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid));
             }
             _ => (),
         }
@@ -182,11 +189,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     tcx.hir().par_body_owners(|item_def_id| {
         let def_kind = tcx.def_kind(item_def_id);
         if !matches!(def_kind, DefKind::AnonConst) {
-            tcx.ensure().typeck(item_def_id);
+            tcx.ensure_ok().typeck(item_def_id);
         }
     });
 
-    tcx.ensure().check_unused_traits(());
+    tcx.ensure_ok().check_unused_traits(());
 }
 
 /// Lower a [`hir::Ty`] to a [`Ty`].
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index c2377b4781c..036163b9f14 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -24,7 +24,7 @@ pub(super) fn infer_predicates(
 
     // If new predicates were added then we need to re-calculate
     // all crates since there could be new implied predicates.
-    'outer: loop {
+    loop {
         let mut predicates_added = false;
 
         // Visit all the crates and infer predicates
@@ -90,7 +90,7 @@ pub(super) fn infer_predicates(
         }
 
         if !predicates_added {
-            break 'outer;
+            break;
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 02cfb57b836..a7760326bb4 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -27,9 +27,6 @@ mod solve;
 
 pub(crate) mod dump;
 
-/// Code for transforming variances.
-mod xform;
-
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { variances_of, crate_variances, ..*providers };
 }
diff --git a/compiler/rustc_hir_analysis/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs
index d0bdca86779..4106c1a5b63 100644
--- a/compiler/rustc_hir_analysis/src/variance/solve.rs
+++ b/compiler/rustc_hir_analysis/src/variance/solve.rs
@@ -12,8 +12,26 @@ use tracing::debug;
 use super::constraints::*;
 use super::terms::VarianceTerm::*;
 use super::terms::*;
-use super::xform::*;
 
+fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance {
+    // Greatest lower bound of the variance lattice as defined in The Paper:
+    //
+    //       *
+    //    -     +
+    //       o
+    match (v1, v2) {
+        (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant,
+
+        (ty::Covariant, ty::Contravariant) => ty::Invariant,
+        (ty::Contravariant, ty::Covariant) => ty::Invariant,
+
+        (ty::Covariant, ty::Covariant) => ty::Covariant,
+
+        (ty::Contravariant, ty::Contravariant) => ty::Contravariant,
+
+        (x, ty::Bivariant) | (ty::Bivariant, x) => x,
+    }
+}
 struct SolveContext<'a, 'tcx> {
     terms_cx: TermsContext<'a, 'tcx>,
     constraints: Vec<Constraint<'a>>,
diff --git a/compiler/rustc_hir_analysis/src/variance/xform.rs b/compiler/rustc_hir_analysis/src/variance/xform.rs
deleted file mode 100644
index 2e9964788e6..00000000000
--- a/compiler/rustc_hir_analysis/src/variance/xform.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use rustc_middle::ty;
-
-pub(crate) fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance {
-    // Greatest lower bound of the variance lattice as
-    // defined in The Paper:
-    //
-    //       *
-    //    -     +
-    //       o
-    match (v1, v2) {
-        (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant,
-
-        (ty::Covariant, ty::Contravariant) => ty::Invariant,
-        (ty::Contravariant, ty::Covariant) => ty::Invariant,
-
-        (ty::Covariant, ty::Covariant) => ty::Covariant,
-
-        (ty::Contravariant, ty::Contravariant) => ty::Contravariant,
-
-        (x, ty::Bivariant) | (ty::Bivariant, x) => x,
-    }
-}
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index afc0f627f69..a91afa51230 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1906,9 +1906,6 @@ impl<'a> State<'a> {
                 }
                 self.pclose();
             }
-            PatKind::Path(ref qpath) => {
-                self.print_qpath(qpath, true);
-            }
             PatKind::Struct(ref qpath, fields, etc) => {
                 self.print_qpath(qpath, true);
                 self.nbsp();
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 28b1a823dae..edc3702d90b 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -49,7 +49,7 @@ pub(crate) fn check_legal_trait_for_method_call(
         };
         return Err(tcx.dcx().emit_err(errors::ExplicitDestructorCall { span, sugg }));
     }
-    tcx.ensure().coherent_trait(trait_id)
+    tcx.ensure_ok().coherent_trait(trait_id)
 }
 
 #[derive(Debug)]
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 153fd6001bb..83acc7dd6af 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -50,7 +50,6 @@ use rustc_infer::traits::{
     IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation,
     PredicateObligations,
 };
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::span_bug;
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::adjustment::{
@@ -1937,7 +1936,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     cond_expr.span.desugaring_kind(),
                     None | Some(DesugaringKind::WhileLoop)
                 )
-                && !in_external_macro(fcx.tcx.sess, cond_expr.span)
+                && !cond_expr.span.in_external_macro(fcx.tcx.sess.source_map())
                 && !matches!(
                     cond_expr.kind,
                     hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index bc076670585..85e949952f8 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1,4 +1,4 @@
-use rustc_errors::{Applicability, Diag, MultiSpan};
+use rustc_errors::{Applicability, Diag, MultiSpan, listify};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::Visitor;
@@ -1016,18 +1016,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 },
                 self.tcx.def_path_str(candidate.item.container_id(self.tcx))
             ),
-            [.., last] if other_methods_in_scope.len() < 5 => {
+            _ if other_methods_in_scope.len() < 5 => {
                 format!(
-                    "the methods of the same name on {} and `{}`",
-                    other_methods_in_scope[..other_methods_in_scope.len() - 1]
-                        .iter()
-                        .map(|c| format!(
-                            "`{}`",
-                            self.tcx.def_path_str(c.item.container_id(self.tcx))
-                        ))
-                        .collect::<Vec<String>>()
-                        .join(", "),
-                    self.tcx.def_path_str(last.item.container_id(self.tcx))
+                    "the methods of the same name on {}",
+                    listify(
+                        &other_methods_in_scope[..other_methods_in_scope.len() - 1],
+                        |c| format!("`{}`", self.tcx.def_path_str(c.item.container_id(self.tcx)))
+                    )
+                    .unwrap_or_default(),
                 )
             }
             _ => format!(
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 1c828591bcb..a519e177fbc 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::codes::*;
 use rustc_errors::{
-    Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize,
+    Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize,
     struct_span_code_err,
 };
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -480,7 +480,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             hir::PatKind::Binding(_, _, _, _)
             | hir::PatKind::Struct(_, _, _)
             | hir::PatKind::TupleStruct(_, _, _)
-            | hir::PatKind::Path(_)
             | hir::PatKind::Tuple(_, _)
             | hir::PatKind::Box(_)
             | hir::PatKind::Ref(_, _)
@@ -1659,8 +1658,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         hir_ty: Option<&'tcx hir::Ty<'tcx>>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented");
-
         match kind {
             hir::UnsafeBinderCastKind::Wrap => {
                 let ascribed_ty =
@@ -2191,13 +2188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             if !missing_mandatory_fields.is_empty() {
                 let s = pluralize!(missing_mandatory_fields.len());
-                let fields: Vec<_> =
-                    missing_mandatory_fields.iter().map(|f| format!("`{f}`")).collect();
-                let fields = match &fields[..] {
-                    [] => unreachable!(),
-                    [only] => only.to_string(),
-                    [start @ .., last] => format!("{} and {last}", start.join(", ")),
-                };
+                let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap();
                 self.dcx()
                     .struct_span_err(
                         span.shrink_to_hi(),
@@ -2554,25 +2545,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .partition(|field| field.2);
         err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field");
         if !remaining_private_fields.is_empty() {
-            let remaining_private_fields_len = remaining_private_fields.len();
-            let names = match &remaining_private_fields
-                .iter()
-                .map(|(name, _, _)| name)
-                .collect::<Vec<_>>()[..]
-            {
-                _ if remaining_private_fields_len > 6 => String::new(),
-                [name] => format!("`{name}` "),
-                [names @ .., last] => {
-                    let names = names.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
-                    format!("{} and `{last}` ", names.join(", "))
-                }
-                [] => bug!("expected at least one private field to report"),
+            let names = if remaining_private_fields.len() > 6 {
+                String::new()
+            } else {
+                format!(
+                    "{} ",
+                    listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`"))
+                        .expect("expected at least one private field to report")
+                )
             };
             err.note(format!(
                 "{}private field{s} {names}that {were} not provided",
                 if used_fields.is_empty() { "" } else { "...and other " },
-                s = pluralize!(remaining_private_fields_len),
-                were = pluralize!("was", remaining_private_fields_len),
+                s = pluralize!(remaining_private_fields.len()),
+                were = pluralize!("was", remaining_private_fields.len()),
             ));
         }
 
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 1f48b703e4a..d37c68f82fb 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -11,10 +11,9 @@ use hir::def::DefKind;
 use hir::pat_util::EnumerateAndAdjustIterator as _;
 use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, Res};
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::{HirId, PatKind};
+use rustc_hir::{self as hir, HirId, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::place::ProjectionKind;
 // Export these here so that Clippy can use them.
@@ -564,11 +563,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                         // FIXME(never_patterns): does this do what I expect?
                         needs_to_be_read = true;
                     }
-                    PatKind::Path(qpath) => {
+                    PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
                         // A `Path` pattern is just a name like `Foo`. This is either a
                         // named constant or else it refers to an ADT variant
 
-                        let res = self.cx.typeck_results().qpath_res(qpath, pat.hir_id);
+                        let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
                         match res {
                             Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
                                 // Named constants have to be equated with the value
@@ -581,7 +580,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                                 // Otherwise, this is a struct/enum variant, and so it's
                                 // only a read if we need to read the discriminant.
                                 needs_to_be_read |=
-                                    self.is_multivariant_adt(place.place.ty(), pat.span);
+                                    self.is_multivariant_adt(place.place.ty(), *span);
                             }
                         }
                     }
@@ -1801,8 +1800,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                 }
             }
 
-            PatKind::Path(_)
-            | PatKind::Binding(.., None)
+            PatKind::Binding(.., None)
             | PatKind::Expr(..)
             | PatKind::Range(..)
             | PatKind::Never
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 8e647ad3c6a..9277d71234f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -253,6 +253,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
+        let mut expr_ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
+
         for a in &adj {
             match a.kind {
                 Adjust::NeverToAny => {
@@ -266,7 +268,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         None,
                         expr.span,
                         overloaded_deref.method_call(self.tcx),
-                        self.tcx.mk_args(&[a.target.into()]),
+                        self.tcx.mk_args(&[expr_ty.into()]),
                     );
                 }
                 Adjust::Deref(None) => {
@@ -283,6 +285,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // No effects to enforce here.
                 }
             }
+
+            expr_ty = a.target;
         }
 
         let autoborrow_mut = adj.iter().any(|adj| {
@@ -1261,7 +1265,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             fn provided_kind(
                 &mut self,
-                _preceding_args: &[ty::GenericArg<'tcx>],
                 param: &ty::GenericParamDef,
                 arg: &GenericArg<'tcx>,
             ) -> ty::GenericArg<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 8e78fb3e219..bbe65371496 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -4,8 +4,7 @@ use itertools::Itertools;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::codes::*;
 use rustc_errors::{
-    Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an,
-    display_list_with_comma_and, pluralize,
+    Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, listify, pluralize,
 };
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -1147,6 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 Some(self.param_env.and(trace.values)),
                                 e,
                                 true,
+                                None,
                             );
                         }
                     }
@@ -2461,7 +2461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 param.span,
                                 format!(
                                     "{} need{} to match the {} type of this parameter",
-                                    display_list_with_comma_and(&other_param_matched_names),
+                                    listify(&other_param_matched_names, |n| n.to_string())
+                                        .unwrap_or_default(),
                                     pluralize!(if other_param_matched_names.len() == 1 {
                                         0
                                     } else {
@@ -2476,7 +2477,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 format!(
                                     "this parameter needs to match the {} type of {}",
                                     matched_ty,
-                                    display_list_with_comma_and(&other_param_matched_names),
+                                    listify(&other_param_matched_names, |n| n.to_string())
+                                        .unwrap_or_default(),
                                 ),
                             );
                         }
@@ -2522,7 +2524,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             generic_param.span,
                             format!(
                                 "{} {} reference this parameter `{}`",
-                                display_list_with_comma_and(&param_idents_matching),
+                                listify(&param_idents_matching, |n| n.to_string())
+                                    .unwrap_or_default(),
                                 if param_idents_matching.len() == 2 { "both" } else { "all" },
                                 generic_param.name.ident().name,
                             ),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index d432199f037..b77e6de52ff 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -31,12 +31,12 @@ use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
 /// functions, closures, and `const`s, including performing type inference
 /// with [`InferCtxt`].
 ///
-/// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures*
-/// and thus does not perform type inference.
+/// This is in contrast to `rustc_hir_analysis::collect::ItemCtxt`, which is
+/// used to type-check item *signatures* and thus does not perform type
+/// inference.
 ///
-/// See [`ItemCtxt`]'s docs for more.
+/// See `ItemCtxt`'s docs for more.
 ///
-/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
 /// [`InferCtxt`]: infer::InferCtxt
 pub(crate) struct FnCtxt<'a, 'tcx> {
     pub(super) body_id: LocalDefId,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 928010c03c2..217ebd9cd2b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -4,17 +4,16 @@ use core::iter;
 use hir::def_id::LocalDefId;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_data_structures::packed::Pu128;
-use rustc_errors::{Applicability, Diag, MultiSpan};
-use rustc_hir as hir;
+use rustc_errors::{Applicability, Diag, MultiSpan, listify};
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
-    Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind, expr_needs_parens,
+    self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
+    GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
+    WherePredicateKind, expr_needs_parens,
 };
-use rustc_hir_analysis::collect::suggest_impl_trait;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
-use rustc_middle::lint::in_external_macro;
+use rustc_hir_analysis::suggest_impl_trait;
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::span_bug;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -770,7 +769,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // If the expression is from an external macro, then do not suggest
                         // adding a semicolon, because there's nowhere to put it.
                         // See issue #81943.
-                        && !in_external_macro(self.tcx.sess, expression.span) =>
+                        && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
                 {
                     if needs_block {
                         err.multipart_suggestion(
@@ -1422,8 +1421,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // since the user probably just misunderstood how `let else`
         // and `&&` work together.
         if let Some((_, hir::Node::LetStmt(local))) = cond_parent
-            && let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) =
-                &local.pat.kind
+            && let hir::PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
+            | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
             && let hir::QPath::Resolved(None, path) = qpath
             && let Some(did) = path
                 .res
@@ -1836,16 +1835,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 error.obligation.predicate,
                             ));
                         }
-                        [errors @ .., last] => {
+                        _ => {
                             diag.help(format!(
                                 "`Clone` is not implemented because the following trait bounds \
-                                 could not be satisfied: {} and `{}`",
-                                errors
-                                    .iter()
-                                    .map(|e| format!("`{}`", e.obligation.predicate))
-                                    .collect::<Vec<_>>()
-                                    .join(", "),
-                                last.obligation.predicate,
+                                 could not be satisfied: {}",
+                                listify(&errors, |e| format!("`{}`", e.obligation.predicate))
+                                    .unwrap(),
                             ));
                         }
                     }
@@ -2265,7 +2260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         expr_ty: Ty<'tcx>,
     ) -> bool {
-        if in_external_macro(self.tcx.sess, expr.span) {
+        if expr.span.in_external_macro(self.tcx.sess.source_map()) {
             return false;
         }
         if let ty::Adt(expected_adt, args) = expected.kind() {
@@ -2593,14 +2588,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     )> {
         let sess = self.sess();
         let sp = expr.span;
+        let sm = sess.source_map();
 
         // If the span is from an external macro, there's no suggestion we can make.
-        if in_external_macro(sess, sp) {
+        if sp.in_external_macro(sm) {
             return None;
         }
 
-        let sm = sess.source_map();
-
         let replace_prefix = |s: &str, old: &str, new: &str| {
             s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
         };
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 880ee83c80a..5c1c38aeb95 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -413,7 +413,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
 
             fn provided_kind(
                 &mut self,
-                _preceding_args: &[ty::GenericArg<'tcx>],
                 param: &ty::GenericParamDef,
                 arg: &GenericArg<'tcx>,
             ) -> ty::GenericArg<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 5d4e67d1a0e..920418407c0 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -5,6 +5,7 @@
 
 use core::ops::ControlFlow;
 use std::borrow::Cow;
+use std::path::PathBuf;
 
 use hir::Expr;
 use rustc_ast::ast::Mutability;
@@ -177,8 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             })
             | hir::Node::Pat(&hir::Pat {
                 kind:
-                    hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))
-                    | hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
+                    hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
                     | hir::PatKind::TupleStruct(QPath::TypeRelative(rcvr, segment), ..),
                 span,
                 ..
@@ -363,14 +363,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> {
         let mut file = None;
-        let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file);
         let mut err = struct_span_code_err!(
             self.dcx(),
             rcvr_expr.span,
             E0599,
             "cannot write into `{}`",
-            ty_str
+            self.tcx.short_string(rcvr_ty, &mut file),
         );
+        *err.long_ty_path() = file;
         err.span_note(
             rcvr_expr.span,
             "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
@@ -381,11 +381,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 "a writer is needed before this format string",
             );
         };
-        if let Some(file) = file {
-            err.note(format!("the full type name has been written to '{}'", file.display()));
-            err.note("consider using `--verbose` to print the full type name to the console");
-        }
-
         err
     }
 
@@ -596,7 +591,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 (predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string()))
             } else {
                 (
-                    tcx.short_ty_string(rcvr_ty, &mut ty_file),
+                    tcx.short_string(rcvr_ty, &mut ty_file),
                     with_forced_trimmed_paths!(rcvr_ty.to_string()),
                 )
             };
@@ -625,6 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             span,
             item_name,
             &short_ty_str,
+            &mut ty_file,
         ) {
             return guar;
         }
@@ -636,6 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             item_kind,
             item_name,
             &short_ty_str,
+            &mut ty_file,
         ) {
             return guar;
         }
@@ -729,10 +726,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty_str = short_ty_str;
         }
 
-        if let Some(file) = ty_file {
-            err.note(format!("the full type name has been written to '{}'", file.display(),));
-            err.note("consider using `--verbose` to print the full type name to the console");
-        }
         if rcvr_ty.references_error() {
             err.downgrade_to_delayed_bug();
         }
@@ -1315,7 +1308,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
                 let actual_prefix = rcvr_ty.prefix_string(self.tcx);
                 info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
-                let mut long_ty_file = None;
                 let (primary_message, label, notes) = if unimplemented_traits.len() == 1
                     && unimplemented_traits_only
                 {
@@ -1330,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             }
                             let OnUnimplementedNote { message, label, notes, .. } = self
                                 .err_ctxt()
-                                .on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
+                                .on_unimplemented_note(trait_ref, &obligation, &mut ty_file);
                             (message, label, notes)
                         })
                         .unwrap()
@@ -1344,15 +1336,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     )
                 });
                 err.primary_message(primary_message);
-                if let Some(file) = long_ty_file {
-                    err.note(format!(
-                        "the full name for the type has been written to '{}'",
-                        file.display(),
-                    ));
-                    err.note(
-                        "consider using `--verbose` to print the full type name to the console",
-                    );
-                }
                 if let Some(label) = label {
                     custom_span_label = true;
                     err.span_label(span, label);
@@ -2404,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         item_name: Ident,
         ty_str: &str,
+        long_ty_path: &mut Option<PathBuf>,
     ) -> Result<(), ErrorGuaranteed> {
         if let SelfSource::MethodCall(expr) = source {
             for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
@@ -2461,7 +2445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     );
                     if pick.is_ok() {
                         let range_span = parent_expr.span.with_hi(expr.span.hi());
-                        return Err(self.dcx().emit_err(errors::MissingParenthesesInRange {
+                        let mut err = self.dcx().create_err(errors::MissingParenthesesInRange {
                             span,
                             ty_str: ty_str.to_string(),
                             method_name: item_name.as_str().to_string(),
@@ -2470,7 +2454,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 left: range_span.shrink_to_lo(),
                                 right: range_span.shrink_to_hi(),
                             }),
-                        }));
+                        });
+                        *err.long_ty_path() = long_ty_path.take();
+                        return Err(err.emit());
                     }
                 }
             }
@@ -2487,6 +2473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         item_kind: &str,
         item_name: Ident,
         ty_str: &str,
+        long_ty_path: &mut Option<PathBuf>,
     ) -> Result<(), ErrorGuaranteed> {
         let found_candidate = all_traits(self.tcx)
             .into_iter()
@@ -2527,6 +2514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 item_name,
                 ty_str
             );
+            *err.long_ty_path() = long_ty_path.take();
             let concrete_type = if actual.is_integral() { "i32" } else { "f32" };
             match expr.kind {
                 ExprKind::Lit(lit) => {
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index cbd1db2ca25..c947ecde656 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -11,8 +11,8 @@ use rustc_errors::{
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{
-    self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatKind,
-    expr_needs_parens,
+    self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
+    PatExprKind, PatKind, expr_needs_parens,
 };
 use rustc_infer::infer;
 use rustc_middle::traits::PatternOriginExpr;
@@ -243,8 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn downgrade_mut_inside_shared(&self) -> bool {
         // NB: RFC 3627 proposes stabilizing Rule 3 in all editions. If we adopt the same behavior
         // across all editions, this may be removed.
-        self.tcx.features().ref_pat_eat_one_layer_2024()
-            || self.tcx.features().ref_pat_eat_one_layer_2024_structural()
+        self.tcx.features().ref_pat_eat_one_layer_2024_structural()
     }
 
     /// Experimental pattern feature: when do reference patterns match against inherited references?
@@ -312,9 +311,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) {
         let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
 
-        let path_res = match &pat.kind {
-            PatKind::Path(qpath) => {
-                Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
+        let path_res = match pat.kind {
+            PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => {
+                Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span))
             }
             _ => None,
         };
@@ -333,6 +332,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatKind::Wild | PatKind::Err(_) => expected,
             // We allow any type here; we ensure that the type is uninhabited during match checking.
             PatKind::Never => expected,
+            PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => {
+                let ty = self.check_pat_path(
+                    *hir_id,
+                    pat.hir_id,
+                    *span,
+                    qpath,
+                    path_res.unwrap(),
+                    expected,
+                    ti,
+                );
+                self.write_ty(*hir_id, ty);
+                ty
+            }
             PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
             PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
             PatKind::Binding(ba, var_id, ident, sub) => {
@@ -341,9 +353,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
                 self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
             }
-            PatKind::Path(ref qpath) => {
-                self.check_pat_path(pat.hir_id, pat.span, qpath, path_res.unwrap(), expected, ti)
-            }
             PatKind::Struct(ref qpath, fields, has_rest_pat) => {
                 self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
             }
@@ -425,7 +434,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         max_ref_mutbl: MutblCap,
     ) -> (Ty<'tcx>, ByRef, MutblCap) {
         #[cfg(debug_assertions)]
-        if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut {
+        if def_br == ByRef::Yes(Mutability::Mut)
+            && max_ref_mutbl != MutblCap::Mut
+            && self.downgrade_mut_inside_shared()
+        {
             span_bug!(pat.span, "Pattern mutability cap violated!");
         }
         match adjust_mode {
@@ -456,16 +468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | PatKind::Slice(..) => AdjustMode::Peel,
             // A never pattern behaves somewhat like a literal or unit variant.
             PatKind::Never => AdjustMode::Peel,
-            // String and byte-string literals result in types `&str` and `&[u8]` respectively.
-            // All other literals result in non-reference types.
-            // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
-            //
-            // Call `resolve_vars_if_possible` here for inline const blocks.
-            PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
-                ty::Ref(..) => AdjustMode::Pass,
-                _ => AdjustMode::Peel,
-            },
-            PatKind::Path(_) => match opt_path_res.unwrap() {
+            PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => match opt_path_res.unwrap() {
                 // These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
                 // Peeling the reference types too early will cause type checking failures.
                 // Although it would be possible to *also* peel the types of the constants too.
@@ -476,6 +479,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // a reference type wherefore peeling doesn't give up any expressiveness.
                 _ => AdjustMode::Peel,
             },
+
+            // String and byte-string literals result in types `&str` and `&[u8]` respectively.
+            // All other literals result in non-reference types.
+            // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
+            //
+            // Call `resolve_vars_if_possible` here for inline const blocks.
+            PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
+                ty::Ref(..) => AdjustMode::Pass,
+                _ => AdjustMode::Peel,
+            },
+
             // Ref patterns are complicated, we handle them in `check_pat_ref`.
             PatKind::Ref(..) => AdjustMode::Pass,
             // A `_` pattern works with any expected type, so there's no need to do anything.
@@ -1001,7 +1015,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         PatKind::Wild
                         | PatKind::Never
                         | PatKind::Binding(..)
-                        | PatKind::Path(..)
                         | PatKind::Box(..)
                         | PatKind::Deref(_)
                         | PatKind::Ref(..)
@@ -1139,7 +1152,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     fn check_pat_path(
         &self,
-        hir_id: HirId,
+        path_id: HirId,
+        pat_id_for_diag: HirId,
         span: Span,
         qpath: &hir::QPath<'_>,
         path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
@@ -1193,11 +1207,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Type-check the path.
         let (pat_ty, pat_res) =
-            self.instantiate_value_path(segments, opt_ty, res, span, span, hir_id);
+            self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
         if let Err(err) =
             self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty)
         {
-            self.emit_bad_pat_path(err, hir_id, span, res, pat_res, pat_ty, segments);
+            self.emit_bad_pat_path(err, pat_id_for_diag, span, res, pat_res, pat_ty, segments);
         }
         pat_ty
     }
@@ -2316,22 +2330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // (RFC 3627, Rule 5). If we implement a pattern typing ruleset with Rule 4E
                         // but not Rule 5, we'll need to check that here.
                         debug_assert!(ref_pat_matches_mut_ref);
-                        let err_msg = "mismatched types";
-                        let err = if let Some(span) = pat_prefix_span {
-                            let mut err = self.dcx().struct_span_err(span, err_msg);
-                            err.code(E0308);
-                            err.note("cannot match inherited `&` with `&mut` pattern");
-                            err.span_suggestion_verbose(
-                                span,
-                                "replace this `&mut` pattern with `&`",
-                                "&",
-                                Applicability::MachineApplicable,
-                            );
-                            err
-                        } else {
-                            self.dcx().struct_span_err(pat.span, err_msg)
-                        };
-                        err.emit();
+                        self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
                     }
 
                     pat_info.binding_mode = ByRef::No;
@@ -2340,28 +2339,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     return expected;
                 }
                 InheritedRefMatchRule::EatInner => {
-                    if let ty::Ref(_, _, r_mutbl) = *expected.kind() {
+                    if let ty::Ref(_, _, r_mutbl) = *expected.kind()
+                        && pat_mutbl <= r_mutbl
+                    {
                         // Match against the reference type; don't consume the inherited ref.
-                        pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl);
+                        // NB: The check for compatible pattern and ref type mutability assumes that
+                        // `&` patterns can match against mutable references (RFC 3627, Rule 5). If
+                        // we implement a pattern typing ruleset with Rule 4 (including the fallback
+                        // to matching the inherited ref when the inner ref can't match) but not
+                        // Rule 5, we'll need to check that here.
+                        debug_assert!(ref_pat_matches_mut_ref);
+                        // NB: For RFC 3627's Rule 3, we limit the default binding mode's ref
+                        // mutability to `pat_info.max_ref_mutbl`. If we implement a pattern typing
+                        // ruleset with Rule 4 but not Rule 3, we'll need to check that here.
+                        debug_assert!(self.downgrade_mut_inside_shared());
+                        let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl());
+                        pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap);
                     } else {
-                        // The expected type isn't a reference, so match against the inherited ref.
+                        // The reference pattern can't match against the expected type, so try
+                        // matching against the inherited ref instead.
                         if pat_mutbl > inh_mut {
-                            // We can't match an inherited shared reference with `&mut`. This will
-                            // be a type error later, since we're matching a reference pattern
-                            // against a non-reference type.
+                            // We can't match an inherited shared reference with `&mut`.
                             // NB: This assumes that `&` patterns can match against mutable
                             // references (RFC 3627, Rule 5). If we implement a pattern typing
                             // ruleset with Rule 4 but not Rule 5, we'll need to check that here.
                             debug_assert!(ref_pat_matches_mut_ref);
-                        } else {
-                            pat_info.binding_mode = ByRef::No;
-                            self.typeck_results
-                                .borrow_mut()
-                                .skipped_ref_pats_mut()
-                                .insert(pat.hir_id);
-                            self.check_pat(inner, expected, pat_info);
-                            return expected;
+                            self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
                         }
+
+                        pat_info.binding_mode = ByRef::No;
+                        self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
+                        self.check_pat(inner, expected, pat_info);
+                        return expected;
                     }
                 }
                 InheritedRefMatchRule::EatBoth => {
@@ -2435,6 +2444,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         Ty::new_ref(self.tcx, region, ty, mutbl)
     }
 
+    fn error_inherited_ref_mutability_mismatch(
+        &self,
+        pat: &'tcx Pat<'tcx>,
+        pat_prefix_span: Option<Span>,
+    ) -> ErrorGuaranteed {
+        let err_msg = "mismatched types";
+        let err = if let Some(span) = pat_prefix_span {
+            let mut err = self.dcx().struct_span_err(span, err_msg);
+            err.code(E0308);
+            err.note("cannot match inherited `&` with `&mut` pattern");
+            err.span_suggestion_verbose(
+                span,
+                "replace this `&mut` pattern with `&`",
+                "&",
+                Applicability::MachineApplicable,
+            );
+            err
+        } else {
+            self.dcx().struct_span_err(pat.span, err_msg)
+        };
+        err.emit()
+    }
+
     fn try_resolve_slice_ty_to_array_ty(
         &self,
         before: &'tcx [Pat<'tcx>],
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index ba635071135..e1bd9ae2e67 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -1,6 +1,7 @@
 use rustc_errors::Applicability;
 use rustc_hir_analysis::autoderef::Autoderef;
 use rustc_infer::infer::InferOk;
+use rustc_infer::traits::{Obligation, ObligationCauseCode};
 use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, OverloadedDeref,
@@ -136,8 +137,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let mut self_ty = adjusted_ty;
             if unsize {
                 // We only unsize arrays here.
-                if let ty::Array(element_ty, _) = adjusted_ty.kind() {
-                    self_ty = Ty::new_slice(self.tcx, *element_ty);
+                if let ty::Array(element_ty, ct) = *adjusted_ty.kind() {
+                    self.register_predicate(Obligation::new(
+                        self.tcx,
+                        self.cause(base_expr.span, ObligationCauseCode::ArrayLen(adjusted_ty)),
+                        self.param_env,
+                        ty::ClauseKind::ConstArgHasType(ct, self.tcx.types.usize),
+                    ));
+                    self_ty = Ty::new_slice(self.tcx, element_ty);
                 } else {
                     continue;
                 }
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index 6dab6468870..563ed7614c6 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -24,7 +24,7 @@ use rustc_middle::util::Providers;
 #[allow(missing_docs)]
 pub fn provide(providers: &mut Providers) {
     providers.hooks.save_dep_graph =
-        |tcx| tcx.sess.time("serialize_dep_graph", || persist::save_dep_graph(tcx.tcx));
+        |tcx| tcx.sess.time("serialize_dep_graph", || persist::save_dep_graph(tcx));
 }
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 12e2bbc968f..ad15b764bcc 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -402,6 +402,18 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
     }
 }
 
+impl<'tcx> ToTrace<'tcx> for ty::ExistentialTraitRef<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
+        TypeTrace {
+            cause: cause.clone(),
+            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(
+                ty::Binder::dummy(a),
+                ty::Binder::dummy(b),
+            )),
+        }
+    }
+}
+
 impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
     fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
@@ -410,3 +422,15 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
         }
     }
 }
+
+impl<'tcx> ToTrace<'tcx> for ty::ExistentialProjection<'tcx> {
+    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
+        TypeTrace {
+            cause: cause.clone(),
+            values: ValuePairs::ExistentialProjection(ExpectedFound::new(
+                ty::Binder::dummy(a),
+                ty::Binder::dummy(b),
+            )),
+        }
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 28eac5b7496..74c8b463fc8 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -170,7 +170,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
             }
 
             ty::ConstKind::Param(_)
-            | ty::ConstKind::Value(_, _)
+            | ty::ConstKind::Value(_)
             | ty::ConstKind::Unevaluated(..)
             | ty::ConstKind::Expr(..)
             | ty::ConstKind::Error(_) => ct.super_fold_with(self),
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 283ebdfa236..c2513a1af19 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -26,7 +26,6 @@ use rustc_macros::extension;
 pub use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
 use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::select;
 pub use rustc_middle::ty::IntVarValue;
@@ -46,6 +45,7 @@ use tracing::{debug, instrument};
 use type_variable::TypeVariableOrigin;
 
 use crate::infer::region_constraints::UndoLog;
+use crate::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
 use crate::traits::{
     self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine,
 };
@@ -64,6 +64,7 @@ pub mod relate;
 pub mod resolve;
 pub(crate) mod snapshot;
 mod type_variable;
+mod unify_key;
 
 /// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper
 /// around `PredicateObligations<'tcx>`, but it has one important property:
@@ -1055,7 +1056,7 @@ impl<'tcx> InferCtxt<'tcx> {
             | ty::ConstKind::Bound(_, _)
             | ty::ConstKind::Placeholder(_)
             | ty::ConstKind::Unevaluated(_)
-            | ty::ConstKind::Value(_, _)
+            | ty::ConstKind::Value(_)
             | ty::ConstKind::Error(_)
             | ty::ConstKind::Expr(_) => ct,
         }
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 9300fc574dc..e924c974a02 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -31,26 +31,14 @@ use crate::traits::query::OutlivesBound;
 pub struct OutlivesEnvironment<'tcx> {
     pub param_env: ty::ParamEnv<'tcx>,
     free_region_map: FreeRegionMap<'tcx>,
-
-    // Contains the implied region bounds in scope for our current body.
-    //
-    // Example:
-    //
-    // ```
-    // fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
-    //   bar(x, y, |y: &'b T| { .. } // body B1)
-    // } // body B0
-    // ```
-    //
-    // Here, when checking the body B0, the list would be `[T: 'a]`, because we
-    // infer that `T` must outlive `'a` from the implied bounds on the
-    // fn declaration.
-    //
-    // For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we
-    // also can see that -- within the closure body! -- `T` must
-    // outlive `'b`. This is not necessarily true outside the closure
-    // body, since the closure may never be called.
+    /// FIXME: Your first reaction may be that this is a bit strange. `RegionBoundPairs`
+    /// does not contain lifetimes, which are instead in the `FreeRegionMap`, and other
+    /// known type outlives are stored in the `known_type_outlives` set. So why do we
+    /// have these at all? It turns out that removing these and using `known_type_outlives`
+    /// everywhere is just enough of a perf regression to matter. This can/should be
+    /// optimized in the future, though.
     region_bound_pairs: RegionBoundPairs<'tcx>,
+    known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
 }
 
 /// "Region-bound pairs" tracks outlives relations that are known to
@@ -59,15 +47,10 @@ pub struct OutlivesEnvironment<'tcx> {
 pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
 
 impl<'tcx> OutlivesEnvironment<'tcx> {
-    /// Create a new `OutlivesEnvironment` without extra outlives bounds.
-    #[inline]
-    pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
-        Self::with_bounds(param_env, vec![])
-    }
-
-    /// Create a new `OutlivesEnvironment` with extra outlives bounds.
-    pub fn with_bounds(
+    /// Create a new `OutlivesEnvironment` from normalized outlives bounds.
+    pub fn from_normalized_bounds(
         param_env: ty::ParamEnv<'tcx>,
+        known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
         extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
     ) -> Self {
         let mut region_relation = TransitiveRelationBuilder::default();
@@ -102,18 +85,21 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
 
         OutlivesEnvironment {
             param_env,
+            known_type_outlives,
             free_region_map: FreeRegionMap { relation: region_relation.freeze() },
             region_bound_pairs,
         }
     }
 
-    /// Borrows current value of the `free_region_map`.
     pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
         &self.free_region_map
     }
 
-    /// Borrows current `region_bound_pairs`.
     pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
         &self.region_bound_pairs
     }
+
+    pub fn known_type_outlives(&self) -> &[ty::PolyTypeOutlivesPredicate<'tcx>] {
+        &self.known_type_outlives
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 0383c81f2af..84e51b18dc5 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -67,7 +67,6 @@ use rustc_middle::ty::{
     self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt,
     TypeFoldable as _, TypeVisitableExt,
 };
-use rustc_span::DUMMY_SP;
 use rustc_type_ir::outlives::{Component, push_outlives_components};
 use smallvec::smallvec;
 use tracing::{debug, instrument};
@@ -142,25 +141,6 @@ impl<'tcx> InferCtxt<'tcx> {
     ) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
         assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
 
-        let normalized_caller_bounds: Vec<_> = outlives_env
-            .param_env
-            .caller_bounds()
-            .iter()
-            .filter_map(|clause| {
-                let outlives = clause.as_type_outlives_clause()?;
-                Some(
-                    deeply_normalize_ty(
-                        outlives,
-                        SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP),
-                    )
-                    // FIXME(-Znext-solver): How do we accurately report an error span here :(
-                    .map_err(|NoSolution| {
-                        (outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP))
-                    }),
-                )
-            })
-            .try_collect()?;
-
         // Must loop since the process of normalizing may itself register region obligations.
         for iteration in 0.. {
             let my_region_obligations = self.take_registered_region_obligations();
@@ -194,7 +174,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     self.tcx,
                     outlives_env.region_bound_pairs(),
                     None,
-                    &normalized_caller_bounds,
+                    outlives_env.known_type_outlives(),
                 );
                 let category = origin.to_constraint_category();
                 outlives.type_must_outlive(origin, sup_type, sub_region, category);
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 6496f38269a..57555db37ab 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -8,7 +8,6 @@ use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify as ut;
 use rustc_index::IndexVec;
 use rustc_macros::{TypeFoldable, TypeVisitable};
-use rustc_middle::infer::unify_key::{RegionVariableValue, RegionVidKey};
 use rustc_middle::ty::{self, ReBound, ReStatic, ReVar, Region, RegionVid, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use tracing::{debug, instrument};
@@ -17,6 +16,7 @@ use self::CombineMapType::*;
 use self::UndoLog::*;
 use super::{MiscVariable, RegionVariableOrigin, Rollback, SubregionOrigin};
 use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
+use crate::infer::unify_key::{RegionVariableValue, RegionVidKey};
 
 mod leak_check;
 
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 21c47967ead..ce2d07f4af9 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -4,7 +4,6 @@ use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
-use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::visit::MaxUniverse;
 use rustc_middle::ty::{
@@ -18,6 +17,7 @@ use super::{
     PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
 };
 use crate::infer::type_variable::TypeVariableValue;
+use crate::infer::unify_key::ConstVariableValue;
 use crate::infer::{InferCtxt, RegionVariableOrigin, relate};
 
 impl<'tcx> InferCtxt<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
index 394e07a81e7..3a47b13665d 100644
--- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
@@ -1,7 +1,6 @@
 use std::ops::Range;
 
 use rustc_data_structures::{snapshot_vec as sv, unify as ut};
-use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
 use rustc_type_ir::visit::TypeVisitableExt;
@@ -10,6 +9,7 @@ use ut::UnifyKey;
 
 use super::VariableLengths;
 use crate::infer::type_variable::TypeVariableOrigin;
+use crate::infer::unify_key::{ConstVariableValue, ConstVidKey};
 use crate::infer::{ConstVariableOrigin, InferCtxt, RegionVariableOrigin, UnificationTable};
 
 fn vars_since_snapshot<'tcx, T>(
diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
index 713389f4618..ba7d8f588e6 100644
--- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
@@ -2,10 +2,10 @@ use std::marker::PhantomData;
 
 use rustc_data_structures::undo_log::{Rollback, UndoLogs};
 use rustc_data_structures::{snapshot_vec as sv, unify as ut};
-use rustc_middle::infer::unify_key::{ConstVidKey, RegionVidKey};
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
 use tracing::debug;
 
+use crate::infer::unify_key::{ConstVidKey, RegionVidKey};
 use crate::infer::{InferCtxtInner, region_constraints, type_variable};
 use crate::traits;
 
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_infer/src/infer/unify_key.rs
index 7f9211043d6..3ba8aea1d3a 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_infer/src/infer/unify_key.rs
@@ -2,23 +2,18 @@ use std::cmp;
 use std::marker::PhantomData;
 
 use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
+use rustc_middle::{bug, ty};
 use rustc_span::Span;
 use rustc_span::def_id::DefId;
 
-use crate::ty::{self, Ty, TyCtxt};
-
-pub trait ToType {
-    fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
-}
-
 #[derive(Copy, Clone, Debug)]
-pub enum RegionVariableValue<'tcx> {
+pub(crate) enum RegionVariableValue<'tcx> {
     Known { value: ty::Region<'tcx> },
     Unknown { universe: ty::UniverseIndex },
 }
 
 #[derive(PartialEq, Copy, Clone, Debug)]
-pub struct RegionVidKey<'tcx> {
+pub(crate) struct RegionVidKey<'tcx> {
     pub vid: ty::RegionVid,
     pub phantom: PhantomData<RegionVariableValue<'tcx>>,
 }
@@ -44,7 +39,8 @@ impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
     }
 }
 
-pub struct RegionUnificationError;
+pub(crate) struct RegionUnificationError;
+
 impl<'tcx> UnifyValue for RegionVariableValue<'tcx> {
     type Error = RegionUnificationError;
 
@@ -100,7 +96,7 @@ pub struct ConstVariableOrigin {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub enum ConstVariableValue<'tcx> {
+pub(crate) enum ConstVariableValue<'tcx> {
     Known { value: ty::Const<'tcx> },
     Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex },
 }
@@ -108,7 +104,7 @@ pub enum ConstVariableValue<'tcx> {
 impl<'tcx> ConstVariableValue<'tcx> {
     /// If this value is known, returns the const it is known to be.
     /// Otherwise, `None`.
-    pub fn known(&self) -> Option<ty::Const<'tcx>> {
+    pub(crate) fn known(&self) -> Option<ty::Const<'tcx>> {
         match *self {
             ConstVariableValue::Unknown { .. } => None,
             ConstVariableValue::Known { value } => Some(value),
@@ -117,7 +113,7 @@ impl<'tcx> ConstVariableValue<'tcx> {
 }
 
 #[derive(PartialEq, Copy, Clone, Debug)]
-pub struct ConstVidKey<'tcx> {
+pub(crate) struct ConstVidKey<'tcx> {
     pub vid: ty::ConstVid,
     pub phantom: PhantomData<ty::Const<'tcx>>,
 }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 241bc35857a..8a121c5a865 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -26,7 +26,6 @@ use rustc_parse::{
 };
 use rustc_passes::{abi_test, input_stats, layout_test};
 use rustc_resolve::Resolver;
-use rustc_session::code_stats::VTableSizeInfo;
 use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
 use rustc_session::cstore::Untracked;
 use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name};
@@ -269,6 +268,7 @@ fn configure_and_expand(
 
     resolver.resolve_crate(&krate);
 
+    CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate);
     krate
 }
 
@@ -833,20 +833,20 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     sess.time("misc_checking_1", || {
         parallel!(
             {
-                sess.time("looking_for_entry_point", || tcx.ensure().entry_fn(()));
+                sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(()));
 
                 sess.time("looking_for_derive_registrar", || {
-                    tcx.ensure().proc_macro_decls_static(())
+                    tcx.ensure_ok().proc_macro_decls_static(())
                 });
 
                 CStore::from_tcx(tcx).report_unused_deps(tcx);
             },
             {
                 tcx.hir().par_for_each_module(|module| {
-                    tcx.ensure().check_mod_loops(module);
-                    tcx.ensure().check_mod_attrs(module);
-                    tcx.ensure().check_mod_naked_functions(module);
-                    tcx.ensure().check_mod_unstable_api_usage(module);
+                    tcx.ensure_ok().check_mod_loops(module);
+                    tcx.ensure_ok().check_mod_attrs(module);
+                    tcx.ensure_ok().check_mod_naked_functions(module);
+                    tcx.ensure_ok().check_mod_unstable_api_usage(module);
                 });
             },
             {
@@ -859,8 +859,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
                 // since they might not otherwise get called.
                 // This marks the corresponding crate-level attributes
                 // as used, and ensures that their values are valid.
-                tcx.ensure().limits(());
-                tcx.ensure().stability_index(());
+                tcx.ensure_ok().limits(());
+                tcx.ensure_ok().stability_index(());
             }
         );
     });
@@ -869,7 +869,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     sess.time("MIR_coroutine_by_move_body", || {
         tcx.hir().par_body_owners(|def_id| {
             if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) {
-                tcx.ensure_with_value().coroutine_by_move_body_def_id(def_id);
+                tcx.ensure_done().coroutine_by_move_body_def_id(def_id);
             }
         });
     });
@@ -884,13 +884,13 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
         tcx.hir().par_body_owners(|def_id| {
             // Run unsafety check because it's responsible for stealing and
             // deallocating THIR.
-            tcx.ensure().check_unsafety(def_id);
-            tcx.ensure().mir_borrowck(def_id)
+            tcx.ensure_ok().check_unsafety(def_id);
+            tcx.ensure_ok().mir_borrowck(def_id)
         });
     });
     sess.time("MIR_effect_checking", || {
         tcx.hir().par_body_owners(|def_id| {
-            tcx.ensure().has_ffi_unwind_calls(def_id);
+            tcx.ensure_ok().has_ffi_unwind_calls(def_id);
 
             // If we need to codegen, ensure that we emit all errors from
             // `mir_drops_elaborated_and_const_checked` now, to avoid discovering
@@ -898,15 +898,15 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
             if tcx.sess.opts.output_types.should_codegen()
                 || tcx.hir().body_const_context(def_id).is_some()
             {
-                tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
+                tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id);
             }
         });
     });
     sess.time("coroutine_obligations", || {
         tcx.hir().par_body_owners(|def_id| {
             if tcx.is_coroutine(def_id.to_def_id()) {
-                tcx.ensure().mir_coroutine_witnesses(def_id);
-                tcx.ensure().check_coroutine_obligations(
+                tcx.ensure_ok().mir_coroutine_witnesses(def_id);
+                tcx.ensure_ok().check_coroutine_obligations(
                     tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
                 );
             }
@@ -951,15 +951,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
     sess.time("misc_checking_3", || {
         parallel!(
             {
-                tcx.ensure().effective_visibilities(());
+                tcx.ensure_ok().effective_visibilities(());
 
                 parallel!(
                     {
-                        tcx.ensure().check_private_in_public(());
+                        tcx.ensure_ok().check_private_in_public(());
                     },
                     {
-                        tcx.hir()
-                            .par_for_each_module(|module| tcx.ensure().check_mod_deathness(module));
+                        tcx.hir().par_for_each_module(|module| {
+                            tcx.ensure_ok().check_mod_deathness(module)
+                        });
                     },
                     {
                         sess.time("lint_checking", || {
@@ -967,14 +968,14 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
                         });
                     },
                     {
-                        tcx.ensure().clashing_extern_declarations(());
+                        tcx.ensure_ok().clashing_extern_declarations(());
                     }
                 );
             },
             {
                 sess.time("privacy_checking_modules", || {
                     tcx.hir().par_for_each_module(|module| {
-                        tcx.ensure().check_mod_privacy(module);
+                        tcx.ensure_ok().check_mod_privacy(module);
                     });
                 });
             }
@@ -982,97 +983,13 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
 
         // This check has to be run after all lints are done processing. We don't
         // define a lint filter, as all lint checks should have finished at this point.
-        sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None));
+        sess.time("check_lint_expectations", || tcx.ensure_ok().check_expectations(None));
 
         // This query is only invoked normally if a diagnostic is emitted that needs any
         // diagnostic item. If the crate compiles without checking any diagnostic items,
         // we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
         let _ = tcx.all_diagnostic_items(());
     });
-
-    if sess.opts.unstable_opts.print_vtable_sizes {
-        let traits = tcx.traits(LOCAL_CRATE);
-
-        for &tr in traits {
-            if !tcx.is_dyn_compatible(tr) {
-                continue;
-            }
-
-            let name = ty::print::with_no_trimmed_paths!(tcx.def_path_str(tr));
-
-            let mut first_dsa = true;
-
-            // Number of vtable entries, if we didn't have upcasting
-            let mut entries_ignoring_upcasting = 0;
-            // Number of vtable entries needed solely for upcasting
-            let mut entries_for_upcasting = 0;
-
-            let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, tr));
-
-            // A slightly edited version of the code in
-            // `rustc_trait_selection::traits::vtable::vtable_entries`, that works without self
-            // type and just counts number of entries.
-            //
-            // Note that this is technically wrong, for traits which have associated types in
-            // supertraits:
-            //
-            //   trait A: AsRef<Self::T> + AsRef<()> { type T; }
-            //
-            // Without self type we can't normalize `Self::T`, so we can't know if `AsRef<Self::T>`
-            // and `AsRef<()>` are the same trait, thus we assume that those are different, and
-            // potentially over-estimate how many vtable entries there are.
-            //
-            // Similarly this is wrong for traits that have methods with possibly-impossible bounds.
-            // For example:
-            //
-            //   trait B<T> { fn f(&self) where T: Copy; }
-            //
-            // Here `dyn B<u8>` will have 4 entries, while `dyn B<String>` will only have 3.
-            // However, since we don't know `T`, we can't know if `T: Copy` holds or not,
-            // thus we lean on the bigger side and say it has 4 entries.
-            traits::vtable::prepare_vtable_segments(tcx, trait_ref, |segment| {
-                match segment {
-                    traits::vtable::VtblSegment::MetadataDSA => {
-                        // If this is the first dsa, it would be included either way,
-                        // otherwise it's needed for upcasting
-                        if std::mem::take(&mut first_dsa) {
-                            entries_ignoring_upcasting += 3;
-                        } else {
-                            entries_for_upcasting += 3;
-                        }
-                    }
-
-                    traits::vtable::VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                        // Lookup the shape of vtable for the trait.
-                        let own_existential_entries =
-                            tcx.own_existential_vtable_entries(trait_ref.def_id());
-
-                        // The original code here ignores the method if its predicates are
-                        // impossible. We can't really do that as, for example, all not trivial
-                        // bounds on generic parameters are impossible (since we don't know the
-                        // parameters...), see the comment above.
-                        entries_ignoring_upcasting += own_existential_entries.len();
-
-                        if emit_vptr {
-                            entries_for_upcasting += 1;
-                        }
-                    }
-                }
-
-                std::ops::ControlFlow::Continue::<std::convert::Infallible>(())
-            });
-
-            sess.code_stats.record_vtable_size(tr, &name, VTableSizeInfo {
-                trait_name: name.clone(),
-                entries: entries_ignoring_upcasting + entries_for_upcasting,
-                entries_ignoring_upcasting,
-                entries_for_upcasting,
-                upcasting_cost_percent: entries_for_upcasting as f64
-                    / entries_ignoring_upcasting as f64
-                    * 100.,
-            })
-        }
-    }
 }
 
 /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
@@ -1091,7 +1008,7 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
                     )
                 }) =>
             {
-                tcx.ensure().trigger_delayed_bug(def_id);
+                tcx.ensure_ok().trigger_delayed_bug(def_id);
             }
 
             // Bare `#[rustc_error]`.
@@ -1153,12 +1070,6 @@ pub(crate) fn start_codegen<'tcx>(
         tcx.sess.code_stats.print_type_sizes();
     }
 
-    if tcx.sess.opts.unstable_opts.print_vtable_sizes {
-        let crate_name = tcx.crate_name(LOCAL_CRATE);
-
-        tcx.sess.code_stats.print_vtable_sizes(crate_name);
-    }
-
     codegen
 }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 9495030f124..fb69dd54811 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -8,12 +8,12 @@ use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::emitter::HumanReadableErrorType;
 use rustc_errors::{ColorConfig, registry};
 use rustc_session::config::{
-    BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel, CoverageOptions,
-    DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
-    FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay,
-    LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig,
-    OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes,
-    PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath,
+    AutoDiff, BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel,
+    CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation,
+    Externs, FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage,
+    InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans,
+    NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
+    Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath,
     SymbolManglingVersion, WasiExecModel, build_configuration, build_session_options,
     rustc_optgroups,
 };
@@ -760,6 +760,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(allow_features, Some(vec![String::from("lang_items")]));
     tracked!(always_encode_mir, true);
     tracked!(assume_incomplete_release, true);
+    tracked!(autodiff, vec![AutoDiff::Print]);
     tracked!(binary_dep_depinfo, true);
     tracked!(box_noalias, false);
     tracked!(
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index e8a4e9a84c4..e2bafbed6e1 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -29,7 +29,6 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_hir::intravisit::FnKind as HirFnKind;
 use rustc_hir::{Body, FnDecl, GenericParamKind, PatKind, PredicateOrigin};
 use rustc_middle::bug;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
@@ -2029,7 +2028,7 @@ impl ExplicitOutlivesRequirements {
                 }
 
                 let span = bound.span().find_ancestor_inside(predicate_span)?;
-                if in_external_macro(tcx.sess, span) {
+                if span.in_external_macro(tcx.sess.source_map()) {
                     return None;
                 }
 
diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
index da6dd8161ee..946dbc34f71 100644
--- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
+++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
@@ -135,7 +135,7 @@ pub(super) fn unexpected_cfg_name(
     };
 
     let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
-    let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span);
+    let is_from_external_macro = name_span.in_external_macro(sess.source_map());
     let mut is_feature_cfg = name == sym::feature;
 
     let code_sugg = if is_feature_cfg && is_from_cargo {
@@ -281,7 +281,7 @@ pub(super) fn unexpected_cfg_value(
         .collect();
 
     let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
-    let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span);
+    let is_from_external_macro = name_span.in_external_macro(sess.source_map());
 
     // Show the full list if all possible values for a given name, but don't do it
     // for names as the possibilities could be very long
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index 44f86535527..d251b4b7459 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -25,8 +25,8 @@ use rustc_span::{Span, Symbol};
 use rustc_trait_selection::errors::{
     AddPreciseCapturingForOvercapture, impl_trait_overcapture_suggestion,
 };
+use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
 use rustc_trait_selection::traits::ObligationCtxt;
-use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt;
 
 use crate::{LateContext, LateLintPass, fluent_generated as fluent};
 
@@ -190,9 +190,7 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
             let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
             let ocx = ObligationCtxt::new(&infcx);
             let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default();
-            let implied_bounds =
-                infcx.implied_bounds_tys_compat(param_env, parent_def_id, &assumed_wf_tys, false);
-            OutlivesEnvironment::with_bounds(param_env, implied_bounds)
+            OutlivesEnvironment::new(&infcx, parent_def_id, param_env, assumed_wf_tys)
         }),
     });
 }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 166ff60f7e1..546df4497ad 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -6,7 +6,7 @@ use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
     AmbigArg, BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat,
-    PatKind, Path, PathSegment, QPath, Ty, TyKind,
+    PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Ty, TyKind,
 };
 use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -164,11 +164,9 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
             TyKind::Path(QPath::Resolved(_, path)) => {
                 if lint_ty_kind_usage(cx, &path.res) {
                     let span = match cx.tcx.parent_hir_node(ty.hir_id) {
-                        Node::Pat(Pat {
-                            kind:
-                                PatKind::Path(qpath)
-                                | PatKind::TupleStruct(qpath, ..)
-                                | PatKind::Struct(qpath, ..),
+                        Node::PatExpr(PatExpr { kind: PatExprKind::Path(qpath), .. })
+                        | Node::Pat(Pat {
+                            kind: PatKind::TupleStruct(qpath, ..) | PatKind::Struct(qpath, ..),
                             ..
                         })
                         | Node::Expr(
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index c6d7b839e19..826ecc22c24 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -458,7 +458,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
         || {
             tcx.sess.time("module_lints", || {
                 // Run per-module lints
-                tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module));
+                tcx.hir().par_for_each_module(|module| tcx.ensure_ok().lint_mod(module));
             });
         },
     );
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
index 9fde35f82d8..35db8632625 100644
--- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
+++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
@@ -37,7 +37,7 @@ declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTAB
 impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         let def_id = item.owner_id.to_def_id();
-        // NOTE(nbdd0121): use `object_safety_violations` instead of `is_dyn_compatible` because
+        // NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because
         // the latter will report `where_clause_object_safety` lint.
         if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
             && cx.tcx.is_dyn_compatible(def_id)
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 6f047b4da49..648d0675627 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -2,7 +2,6 @@ use rustc_ast as ast;
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::{bug, ty};
 use rustc_parse_format::{ParseMode, Parser, Piece};
 use rustc_session::lint::FutureIncompatibilityReason;
@@ -100,7 +99,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
 
     let (span, panic, symbol) = panic_call(cx, f);
 
-    if in_external_macro(cx.sess(), span) {
+    if span.in_external_macro(cx.sess().source_map()) {
         // Nothing that can be done about it in the current crate.
         return;
     }
@@ -229,14 +228,15 @@ fn check_panic_str<'tcx>(
 
     let (span, _, _) = panic_call(cx, f);
 
-    if in_external_macro(cx.sess(), span) && in_external_macro(cx.sess(), arg.span) {
+    let sm = cx.sess().source_map();
+    if span.in_external_macro(sm) && arg.span.in_external_macro(sm) {
         // Nothing that can be done about it in the current crate.
         return;
     }
 
     let fmt_span = arg.span.source_callsite();
 
-    let (snippet, style) = match cx.sess().psess.source_map().span_to_snippet(fmt_span) {
+    let (snippet, style) = match sm.span_to_snippet(fmt_span) {
         Ok(snippet) => {
             // Count the number of `#`s between the `r` and `"`.
             let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
@@ -283,7 +283,7 @@ fn check_panic_str<'tcx>(
 /// Given the span of `some_macro!(args);`, gives the span of `(` and `)`,
 /// and the type of (opening) delimiter used.
 fn find_delimiters(cx: &LateContext<'_>, span: Span) -> Option<(Span, Span, char)> {
-    let snippet = cx.sess().psess.source_map().span_to_snippet(span).ok()?;
+    let snippet = cx.sess().source_map().span_to_snippet(span).ok()?;
     let (open, open_ch) = snippet.char_indices().find(|&(_, c)| "([{".contains(c))?;
     let close = snippet.rfind(|c| ")]}".contains(c))?;
     Some((
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index e09049f322f..0c180ab9570 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -1,7 +1,7 @@
 use rustc_abi::ExternAbi;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatKind};
+use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatExprKind, PatKind};
 use rustc_middle::ty;
 use rustc_session::config::CrateType;
 use rustc_session::{declare_lint, declare_lint_pass};
@@ -527,7 +527,11 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
 
     fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
         // Lint for constants that look like binding identifiers (#7526)
-        if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind {
+        if let PatKind::Expr(hir::PatExpr {
+            kind: PatExprKind::Path(hir::QPath::Resolved(None, path)),
+            ..
+        }) = p.kind
+        {
             if let Res::Def(DefKind::Const, _) = path.res {
                 if let [segment] = path.segments {
                     NonUpperCaseGlobals::check_upper_case(
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 3f1e98556ef..7ffe4e4e490 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -42,6 +42,23 @@ macro_rules! pluralize {
     };
 }
 
+/// Grammatical tool for displaying messages to end users in a nice form.
+///
+/// Take a list of items and a function to turn those items into a `String`, and output a display
+/// friendly comma separated list of those items.
+// FIXME(estebank): this needs to be changed to go through the translation machinery.
+pub fn listify<T>(list: &[T], fmt: impl Fn(&T) -> String) -> Option<String> {
+    Some(match list {
+        [only] => fmt(&only),
+        [others @ .., last] => format!(
+            "{} and {}",
+            others.iter().map(|i| fmt(i)).collect::<Vec<_>>().join(", "),
+            fmt(&last),
+        ),
+        [] => return None,
+    })
+}
+
 /// Indicates the confidence in the correctness of a suggestion.
 ///
 /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 35186778671..7ff316ba83a 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -319,7 +319,11 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
   case LLVMRustAttributeKind::NoAlias:
     return Attribute::NoAlias;
   case LLVMRustAttributeKind::NoCapture:
+#if LLVM_VERSION_GE(21, 0)
+    report_fatal_error("NoCapture doesn't exist in LLVM 21");
+#else
     return Attribute::NoCapture;
+#endif
   case LLVMRustAttributeKind::NoCfCheck:
     return Attribute::NoCfCheck;
   case LLVMRustAttributeKind::NoInline:
@@ -431,6 +435,12 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) {
 
 extern "C" LLVMAttributeRef
 LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
+#if LLVM_VERSION_GE(21, 0)
+  // LLVM 21 replaced the NoCapture attribute with Captures(none).
+  if (RustAttr == LLVMRustAttributeKind::NoCapture) {
+    return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none()));
+  }
+#endif
   return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
 }
 
@@ -667,8 +677,6 @@ extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
       unwrap<FunctionType>(Ty), StringRef(Constraints, ConstraintsLen)));
 }
 
-typedef DIBuilder *LLVMRustDIBuilderRef;
-
 template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) {
   return (DIT *)(Ref ? unwrap<MDNode>(Ref) : nullptr);
 }
@@ -677,12 +685,6 @@ template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) {
 #define DIArray DINodeArray
 #define unwrapDI unwrapDIPtr
 
-// FIXME(Zalathar): This is a temporary typedef to avoid churning dozens of
-// bindings that are going to be deleted and replaced with their LLVM-C
-// equivalents, as part of #134009. After that happens, the remaining bindings
-// can be adjusted to use `LLVMDIFlags` instead of relying on this typedef.
-typedef LLVMDIFlags LLVMRustDIFlags;
-
 // Statically assert that `LLVMDIFlags` (C) and `DIFlags` (C++) have the same
 // layout, at least for the flags we know about. This isn't guaranteed, but is
 // likely to remain true, and as long as it is true it makes conversions easy.
@@ -955,7 +957,8 @@ extern "C" LLVMValueRef LLVMRustGetLastInstruction(LLVMBasicBlockRef BB) {
   return nullptr;
 }
 
-extern "C" void LLVMRustEraseInstBefore(LLVMBasicBlockRef bb, LLVMValueRef I) {
+extern "C" void LLVMRustEraseInstUntilInclusive(LLVMBasicBlockRef bb,
+                                                LLVMValueRef I) {
   auto &BB = *unwrap(bb);
   auto &Inst = *unwrap<Instruction>(I);
   auto It = BB.begin();
@@ -963,8 +966,6 @@ extern "C" void LLVMRustEraseInstBefore(LLVMBasicBlockRef bb, LLVMValueRef I) {
     ++It;
   // Make sure we found the Instruction.
   assert(It != BB.end());
-  // We don't want to erase the instruction itself.
-  It--;
   // Delete in rev order to ensure no dangling references.
   while (It != BB.begin()) {
     auto Prev = std::prev(It);
@@ -994,34 +995,34 @@ extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
   unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));
 }
 
-extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) {
-  return new DIBuilder(*unwrap(M));
+extern "C" LLVMDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) {
+  return wrap(new DIBuilder(*unwrap(M)));
 }
 
-extern "C" void LLVMRustDIBuilderDispose(LLVMRustDIBuilderRef Builder) {
-  delete Builder;
+extern "C" void LLVMRustDIBuilderDispose(LLVMDIBuilderRef Builder) {
+  delete unwrap(Builder);
 }
 
-extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) {
-  Builder->finalize();
+extern "C" void LLVMRustDIBuilderFinalize(LLVMDIBuilderRef Builder) {
+  unwrap(Builder)->finalize();
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit(
-    LLVMRustDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef,
+    LLVMDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef,
     const char *Producer, size_t ProducerLen, bool isOptimized,
     const char *Flags, unsigned RuntimeVer, const char *SplitName,
     size_t SplitNameLen, LLVMRustDebugEmissionKind Kind, uint64_t DWOId,
     bool SplitDebugInlining, LLVMRustDebugNameTableKind TableKind) {
   auto *File = unwrapDI<DIFile>(FileRef);
 
-  return wrap(Builder->createCompileUnit(
+  return wrap(unwrap(Builder)->createCompileUnit(
       Lang, File, StringRef(Producer, ProducerLen), isOptimized, Flags,
       RuntimeVer, StringRef(SplitName, SplitNameLen), fromRust(Kind), DWOId,
       SplitDebugInlining, false, fromRust(TableKind)));
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename,
+LLVMRustDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename,
                             size_t FilenameLen, const char *Directory,
                             size_t DirectoryLen, LLVMRustChecksumKind CSKind,
                             const char *Checksum, size_t ChecksumLen,
@@ -1034,29 +1035,29 @@ LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename,
   std::optional<StringRef> oSource{};
   if (Source)
     oSource = StringRef(Source, SourceLen);
-  return wrap(Builder->createFile(StringRef(Filename, FilenameLen),
-                                  StringRef(Directory, DirectoryLen), CSInfo,
-                                  oSource));
+  return wrap(unwrap(Builder)->createFile(StringRef(Filename, FilenameLen),
+                                          StringRef(Directory, DirectoryLen),
+                                          CSInfo, oSource));
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateSubroutineType(LLVMRustDIBuilderRef Builder,
+LLVMRustDIBuilderCreateSubroutineType(LLVMDIBuilderRef Builder,
                                       LLVMMetadataRef ParameterTypes) {
-  return wrap(Builder->createSubroutineType(
+  return wrap(unwrap(Builder)->createSubroutineType(
       DITypeRefArray(unwrap<MDTuple>(ParameterTypes))));
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
     LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
-    unsigned ScopeLine, LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags,
+    unsigned ScopeLine, LLVMDIFlags Flags, LLVMRustDISPFlags SPFlags,
     LLVMValueRef MaybeFn, LLVMMetadataRef TParam, LLVMMetadataRef Decl) {
   DITemplateParameterArray TParams =
       DITemplateParameterArray(unwrap<MDTuple>(TParam));
   DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags);
   DINode::DIFlags llvmFlags = fromRust(Flags);
-  DISubprogram *Sub = Builder->createFunction(
+  DISubprogram *Sub = unwrap(Builder)->createFunction(
       unwrapDI<DIScope>(Scope), StringRef(Name, NameLen),
       StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo,
       unwrapDI<DISubroutineType>(Ty), ScopeLine, llvmFlags, llvmSPFlags,
@@ -1067,15 +1068,15 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
     LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
-    LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) {
+    LLVMDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) {
   DITemplateParameterArray TParams =
       DITemplateParameterArray(unwrap<MDTuple>(TParam));
   DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags);
   DINode::DIFlags llvmFlags = fromRust(Flags);
-  DISubprogram *Sub = Builder->createMethod(
+  DISubprogram *Sub = unwrap(Builder)->createMethod(
       unwrapDI<DIScope>(Scope), StringRef(Name, NameLen),
       StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo,
       unwrapDI<DISubroutineType>(Ty), 0, 0,
@@ -1085,39 +1086,39 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name,
+LLVMRustDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name,
                                  size_t NameLen, uint64_t SizeInBits,
                                  unsigned Encoding) {
-  return wrap(
-      Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding));
+  return wrap(unwrap(Builder)->createBasicType(StringRef(Name, NameLen),
+                                               SizeInBits, Encoding));
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateTypedef(LLVMRustDIBuilderRef Builder,
-                               LLVMMetadataRef Type, const char *Name,
-                               size_t NameLen, LLVMMetadataRef File,
-                               unsigned LineNo, LLVMMetadataRef Scope) {
-  return wrap(Builder->createTypedef(
+LLVMRustDIBuilderCreateTypedef(LLVMDIBuilderRef Builder, LLVMMetadataRef Type,
+                               const char *Name, size_t NameLen,
+                               LLVMMetadataRef File, unsigned LineNo,
+                               LLVMMetadataRef Scope) {
+  return wrap(unwrap(Builder)->createTypedef(
       unwrap<DIType>(Type), StringRef(Name, NameLen), unwrap<DIFile>(File),
       LineNo, unwrapDIPtr<DIScope>(Scope)));
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef PointeeTy,
-    uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace,
-    const char *Name, size_t NameLen) {
-  return wrap(Builder->createPointerType(unwrapDI<DIType>(PointeeTy),
-                                         SizeInBits, AlignInBits, AddressSpace,
-                                         StringRef(Name, NameLen)));
+    LLVMDIBuilderRef Builder, LLVMMetadataRef PointeeTy, uint64_t SizeInBits,
+    uint32_t AlignInBits, unsigned AddressSpace, const char *Name,
+    size_t NameLen) {
+  return wrap(unwrap(Builder)->createPointerType(
+      unwrapDI<DIType>(PointeeTy), SizeInBits, AlignInBits, AddressSpace,
+      StringRef(Name, NameLen)));
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
-    uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags,
+    uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags,
     LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, unsigned RunTimeLang,
     LLVMMetadataRef VTableHolder, const char *UniqueId, size_t UniqueIdLen) {
-  return wrap(Builder->createStructType(
+  return wrap(unwrap(Builder)->createStructType(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
       unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
       fromRust(Flags), unwrapDI<DIType>(DerivedFrom),
@@ -1126,12 +1127,12 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType(
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
-    uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags,
+    uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags,
     LLVMMetadataRef Discriminator, LLVMMetadataRef Elements,
     const char *UniqueId, size_t UniqueIdLen) {
-  return wrap(Builder->createVariantPart(
+  return wrap(unwrap(Builder)->createVariantPart(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
       unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
       fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator),
@@ -1140,36 +1141,36 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
-    uint32_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags,
+    uint32_t AlignInBits, uint64_t OffsetInBits, LLVMDIFlags Flags,
     LLVMMetadataRef Ty) {
-  return wrap(Builder->createMemberType(
+  return wrap(unwrap(Builder)->createMemberType(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
       unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits,
       fromRust(Flags), unwrapDI<DIType>(Ty)));
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
     uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant,
-    LLVMRustDIFlags Flags, LLVMMetadataRef Ty) {
+    LLVMDIFlags Flags, LLVMMetadataRef Ty) {
   llvm::ConstantInt *D = nullptr;
   if (Discriminant) {
     D = unwrap<llvm::ConstantInt>(Discriminant);
   }
-  return wrap(Builder->createVariantMemberType(
+  return wrap(unwrap(Builder)->createVariantMemberType(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
       unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, D,
       fromRust(Flags), unwrapDI<DIType>(Ty)));
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
-    LLVMRustDIFlags Flags, LLVMValueRef val, uint32_t AlignInBits) {
-  return wrap(Builder->createStaticMemberType(
+    LLVMDIFlags Flags, LLVMValueRef val, uint32_t AlignInBits) {
+  return wrap(unwrap(Builder)->createStaticMemberType(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
       unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), fromRust(Flags),
       unwrap<llvm::ConstantInt>(val), llvm::dwarf::DW_TAG_member, AlignInBits));
@@ -1183,21 +1184,21 @@ LLVMRustDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag,
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateLexicalBlock(LLVMRustDIBuilderRef Builder,
+LLVMRustDIBuilderCreateLexicalBlock(LLVMDIBuilderRef Builder,
                                     LLVMMetadataRef Scope, LLVMMetadataRef File,
                                     unsigned Line, unsigned Col) {
-  return wrap(Builder->createLexicalBlock(unwrapDI<DIDescriptor>(Scope),
-                                          unwrapDI<DIFile>(File), Line, Col));
+  return wrap(unwrap(Builder)->createLexicalBlock(
+      unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File), Line, Col));
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File) {
-  return wrap(Builder->createLexicalBlockFile(unwrapDI<DIDescriptor>(Scope),
-                                              unwrapDI<DIFile>(File)));
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File) {
+  return wrap(unwrap(Builder)->createLexicalBlockFile(
+      unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File)));
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name,
     size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
     LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
     bool IsLocalToUnit, LLVMValueRef V, LLVMMetadataRef Decl = nullptr,
@@ -1206,16 +1207,16 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
 
   llvm::DIExpression *InitExpr = nullptr;
   if (llvm::ConstantInt *IntVal = llvm::dyn_cast<llvm::ConstantInt>(InitVal)) {
-    InitExpr = Builder->createConstantValueExpression(
+    InitExpr = unwrap(Builder)->createConstantValueExpression(
         IntVal->getValue().getSExtValue());
   } else if (llvm::ConstantFP *FPVal =
                  llvm::dyn_cast<llvm::ConstantFP>(InitVal)) {
-    InitExpr = Builder->createConstantValueExpression(
+    InitExpr = unwrap(Builder)->createConstantValueExpression(
         FPVal->getValueAPF().bitcastToAPInt().getZExtValue());
   }
 
   llvm::DIGlobalVariableExpression *VarExpr =
-      Builder->createGlobalVariableExpression(
+      unwrap(Builder)->createGlobalVariableExpression(
           unwrapDI<DIDescriptor>(Context), StringRef(Name, NameLen),
           StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File),
           LineNo, unwrapDI<DIType>(Ty), IsLocalToUnit,
@@ -1228,17 +1229,17 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
-    LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope,
+    LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope,
     const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo,
-    LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMRustDIFlags Flags,
-    unsigned ArgNo, uint32_t AlignInBits) {
+    LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMDIFlags Flags, unsigned ArgNo,
+    uint32_t AlignInBits) {
   if (Tag == 0x100) { // DW_TAG_auto_variable
-    return wrap(Builder->createAutoVariable(
+    return wrap(unwrap(Builder)->createAutoVariable(
         unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
         unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve,
         fromRust(Flags), AlignInBits));
   } else {
-    return wrap(Builder->createParameterVariable(
+    return wrap(unwrap(Builder)->createParameterVariable(
         unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ArgNo,
         unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve,
         fromRust(Flags)));
@@ -1246,53 +1247,56 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateArrayType(LLVMRustDIBuilderRef Builder, uint64_t Size,
+LLVMRustDIBuilderCreateArrayType(LLVMDIBuilderRef Builder, uint64_t Size,
                                  uint32_t AlignInBits, LLVMMetadataRef Ty,
                                  LLVMMetadataRef Subscripts) {
-  return wrap(
-      Builder->createArrayType(Size, AlignInBits, unwrapDI<DIType>(Ty),
-                               DINodeArray(unwrapDI<MDTuple>(Subscripts))));
+  return wrap(unwrap(Builder)->createArrayType(
+      Size, AlignInBits, unwrapDI<DIType>(Ty),
+      DINodeArray(unwrapDI<MDTuple>(Subscripts))));
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderGetOrCreateSubrange(LLVMRustDIBuilderRef Builder, int64_t Lo,
+LLVMRustDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo,
                                      int64_t Count) {
-  return wrap(Builder->getOrCreateSubrange(Lo, Count));
+  return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count));
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder,
+LLVMRustDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder,
                                   LLVMMetadataRef *Ptr, unsigned Count) {
   Metadata **DataValue = unwrap(Ptr);
-  return wrap(
-      Builder->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count)).get());
+  return wrap(unwrap(Builder)
+                  ->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count))
+                  .get());
 }
 
-extern "C" void LLVMRustDIBuilderInsertDeclareAtEnd(
-    LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo,
-    uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
-    LLVMBasicBlockRef InsertAtEnd) {
-  Builder->insertDeclare(unwrap(V), unwrap<DILocalVariable>(VarInfo),
-                         Builder->createExpression(
-                             llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
-                         DebugLoc(cast<MDNode>(unwrap(DL))),
-                         unwrap(InsertAtEnd));
+extern "C" void
+LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V,
+                                    LLVMMetadataRef VarInfo, uint64_t *AddrOps,
+                                    unsigned AddrOpsCount, LLVMMetadataRef DL,
+                                    LLVMBasicBlockRef InsertAtEnd) {
+  unwrap(Builder)->insertDeclare(
+      unwrap(V), unwrap<DILocalVariable>(VarInfo),
+      unwrap(Builder)->createExpression(
+          llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
+      DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd));
 }
 
-extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator(
-    LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen,
-    const uint64_t Value[2], unsigned SizeInBits, bool IsUnsigned) {
-  return wrap(Builder->createEnumerator(
+extern "C" LLVMMetadataRef
+LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name,
+                                  size_t NameLen, const uint64_t Value[2],
+                                  unsigned SizeInBits, bool IsUnsigned) {
+  return wrap(unwrap(Builder)->createEnumerator(
       StringRef(Name, NameLen),
       APSInt(APInt(SizeInBits, ArrayRef<uint64_t>(Value, 2)), IsUnsigned)));
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
     uint64_t SizeInBits, uint32_t AlignInBits, LLVMMetadataRef Elements,
     LLVMMetadataRef ClassTy, bool IsScoped) {
-  return wrap(Builder->createEnumerationType(
+  return wrap(unwrap(Builder)->createEnumerationType(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
       unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
       DINodeArray(unwrapDI<MDTuple>(Elements)), unwrapDI<DIType>(ClassTy),
@@ -1300,12 +1304,12 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType(
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
-    uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags,
+    uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags,
     LLVMMetadataRef Elements, unsigned RunTimeLang, const char *UniqueId,
     size_t UniqueIdLen) {
-  return wrap(Builder->createUnionType(
+  return wrap(unwrap(Builder)->createUnionType(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
       unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits,
       fromRust(Flags), DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang,
@@ -1313,28 +1317,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef Ty) {
   bool IsDefault = false; // FIXME: should we ever set this true?
-  return wrap(Builder->createTemplateTypeParameter(
+  return wrap(unwrap(Builder)->createTemplateTypeParameter(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
       unwrapDI<DIType>(Ty), IsDefault));
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateNameSpace(LLVMRustDIBuilderRef Builder,
+LLVMRustDIBuilderCreateNameSpace(LLVMDIBuilderRef Builder,
                                  LLVMMetadataRef Scope, const char *Name,
                                  size_t NameLen, bool ExportSymbols) {
-  return wrap(Builder->createNameSpace(
+  return wrap(unwrap(Builder)->createNameSpace(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ExportSymbols));
 }
 
 extern "C" void LLVMRustDICompositeTypeReplaceArrays(
-    LLVMRustDIBuilderRef Builder, LLVMMetadataRef CompositeTy,
+    LLVMDIBuilderRef Builder, LLVMMetadataRef CompositeTy,
     LLVMMetadataRef Elements, LLVMMetadataRef Params) {
   DICompositeType *Tmp = unwrapDI<DICompositeType>(CompositeTy);
-  Builder->replaceArrays(Tmp, DINodeArray(unwrap<MDTuple>(Elements)),
-                         DINodeArray(unwrap<MDTuple>(Params)));
+  unwrap(Builder)->replaceArrays(Tmp, DINodeArray(unwrap<MDTuple>(Elements)),
+                                 DINodeArray(unwrap<MDTuple>(Params)));
 }
 
 extern "C" LLVMMetadataRef
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 88ea6e07d6e..62bf34ad5ad 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -118,11 +118,17 @@ struct QueryModifiers {
     /// Generate a `feed` method to set the query's value from another query.
     feedable: Option<Ident>,
 
-    /// Forward the result on ensure if the query gets recomputed, and
-    /// return `Ok(())` otherwise. Only applicable to queries returning
-    /// `Result<T, ErrorGuaranteed>`. The `T` is not returned from `ensure`
-    /// invocations.
-    ensure_forwards_result_if_red: Option<Ident>,
+    /// When this query is called via `tcx.ensure_ok()`, it returns
+    /// `Result<(), ErrorGuaranteed>` instead of `()`. If the query needs to
+    /// be executed, and that execution returns an error, the error result is
+    /// returned to the caller.
+    ///
+    /// If execution is skipped, a synthetic `Ok(())` is returned, on the
+    /// assumption that a query with all-green inputs must have succeeded.
+    ///
+    /// Can only be applied to queries with a return value of
+    /// `Result<_, ErrorGuaranteed>`.
+    return_result_from_ensure_ok: Option<Ident>,
 }
 
 fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
@@ -138,7 +144,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
     let mut depth_limit = None;
     let mut separate_provide_extern = None;
     let mut feedable = None;
-    let mut ensure_forwards_result_if_red = None;
+    let mut return_result_from_ensure_ok = None;
 
     while !input.is_empty() {
         let modifier: Ident = input.parse()?;
@@ -200,8 +206,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
             try_insert!(separate_provide_extern = modifier);
         } else if modifier == "feedable" {
             try_insert!(feedable = modifier);
-        } else if modifier == "ensure_forwards_result_if_red" {
-            try_insert!(ensure_forwards_result_if_red = modifier);
+        } else if modifier == "return_result_from_ensure_ok" {
+            try_insert!(return_result_from_ensure_ok = modifier);
         } else {
             return Err(Error::new(modifier.span(), "unknown query modifier"));
         }
@@ -222,7 +228,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
         depth_limit,
         separate_provide_extern,
         feedable,
-        ensure_forwards_result_if_red,
+        return_result_from_ensure_ok,
     })
 }
 
@@ -354,7 +360,7 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
             eval_always,
             depth_limit,
             separate_provide_extern,
-            ensure_forwards_result_if_red,
+            return_result_from_ensure_ok,
         );
 
         if modifiers.cache.is_some() {
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index d2b5ae53185..6fc84b06647 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -113,6 +113,14 @@ metadata_incompatible_rustc =
     found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
     .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
 
+metadata_incompatible_target_modifiers =
+    mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
+    .note = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}`
+    .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+
+metadata_incompatible_target_modifiers_help_allow = if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch={$flag_name}` to silence this error
+metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$flag_extern_value}` in this crate or `{$flag_name_prefixed}={$flag_local_value}` in `{$extern_crate}`
+
 metadata_incompatible_wasm_link =
     `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
 
@@ -284,6 +292,8 @@ metadata_unknown_link_kind =
 metadata_unknown_link_modifier =
     unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
 
+metadata_unknown_target_modifier_unsafe_allowed = unknown target modifier `{$flag_name}`, requested by `-Cunsafe-allow-abi-mismatch={$flag_name}`
+
 metadata_unsupported_abi =
     ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index a6cd0ecafd0..6bad8312790 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -23,7 +23,10 @@ use rustc_hir::definitions::Definitions;
 use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
-use rustc_session::config::{self, CrateType, ExternLocation};
+use rustc_session::config::{
+    self, CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers,
+    TargetModifier,
+};
 use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
 use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::output::validate_crate_name;
@@ -35,7 +38,9 @@ use tracing::{debug, info, trace};
 
 use crate::errors;
 use crate::locator::{CrateError, CrateLocator, CratePaths};
-use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
+use crate::rmeta::{
+    CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
+};
 
 /// The backend's way to give the crate store access to the metadata in a library.
 /// Note that it returns the raw metadata bytes stored in the library file, whether
@@ -296,6 +301,94 @@ impl CStore {
         }
     }
 
+    fn report_target_modifiers_extended(
+        tcx: TyCtxt<'_>,
+        krate: &Crate,
+        mods: &TargetModifiers,
+        dep_mods: &TargetModifiers,
+        data: &CrateMetadata,
+    ) {
+        let span = krate.spans.inner_span.shrink_to_lo();
+        let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch;
+        let name = tcx.crate_name(LOCAL_CRATE);
+        let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone());
+        let report_diff = |prefix: &String,
+                           opt_name: &String,
+                           flag_local_value: &String,
+                           flag_extern_value: &String| {
+            if allowed_flag_mismatches.contains(&opt_name) {
+                return;
+            }
+            tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
+                span,
+                extern_crate: data.name(),
+                local_crate: name,
+                flag_name: opt_name.clone(),
+                flag_name_prefixed: format!("-{}{}", prefix, opt_name),
+                flag_local_value: flag_local_value.to_string(),
+                flag_extern_value: flag_extern_value.to_string(),
+            });
+        };
+        let mut it1 = mods.iter().map(tmod_extender);
+        let mut it2 = dep_mods.iter().map(tmod_extender);
+        let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
+        let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
+        let no_val = "*".to_string();
+        loop {
+            left_name_val = left_name_val.or_else(|| it1.next());
+            right_name_val = right_name_val.or_else(|| it2.next());
+            match (&left_name_val, &right_name_val) {
+                (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
+                    cmp::Ordering::Equal => {
+                        if l.0.tech_value != r.0.tech_value {
+                            report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &r.1.value_name);
+                        }
+                        left_name_val = None;
+                        right_name_val = None;
+                    }
+                    cmp::Ordering::Greater => {
+                        report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
+                        right_name_val = None;
+                    }
+                    cmp::Ordering::Less => {
+                        report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
+                        left_name_val = None;
+                    }
+                },
+                (Some(l), None) => {
+                    report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
+                    left_name_val = None;
+                }
+                (None, Some(r)) => {
+                    report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
+                    right_name_val = None;
+                }
+                (None, None) => break,
+            }
+        }
+    }
+
+    pub fn report_incompatible_target_modifiers(&self, tcx: TyCtxt<'_>, krate: &Crate) {
+        for flag_name in &tcx.sess.opts.cg.unsafe_allow_abi_mismatch {
+            if !OptionsTargetModifiers::is_target_modifier(flag_name) {
+                tcx.dcx().emit_err(errors::UnknownTargetModifierUnsafeAllowed {
+                    span: krate.spans.inner_span.shrink_to_lo(),
+                    flag_name: flag_name.clone(),
+                });
+            }
+        }
+        let mods = tcx.sess.opts.gather_target_modifiers();
+        for (_cnum, data) in self.iter_crate_data() {
+            if data.is_proc_macro_crate() {
+                continue;
+            }
+            let dep_mods = data.target_modifiers();
+            if mods != dep_mods {
+                Self::report_target_modifiers_extended(tcx, krate, &mods, &dep_mods, data);
+            }
+        }
+    }
+
     pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
         CStore {
             metadata_loader,
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index cefc6498f68..a77f9bc623b 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -739,3 +739,28 @@ pub(crate) struct WasmCAbi {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(metadata_incompatible_target_modifiers)]
+#[help]
+#[note]
+#[help(metadata_incompatible_target_modifiers_help_fix)]
+#[help(metadata_incompatible_target_modifiers_help_allow)]
+pub struct IncompatibleTargetModifiers {
+    #[primary_span]
+    pub span: Span,
+    pub extern_crate: Symbol,
+    pub local_crate: Symbol,
+    pub flag_name: String,
+    pub flag_name_prefixed: String,
+    pub flag_local_value: String,
+    pub flag_extern_value: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(metadata_unknown_target_modifier_unsafe_allowed)]
+pub struct UnknownTargetModifierUnsafeAllowed {
+    #[primary_span]
+    pub span: Span,
+    pub flag_name: String,
+}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index e02c4871f35..2ae4a6a6066 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -29,6 +29,7 @@ use rustc_middle::{bug, implement_ty_decoder};
 use rustc_serialize::opaque::MemDecoder;
 use rustc_serialize::{Decodable, Decoder};
 use rustc_session::Session;
+use rustc_session::config::TargetModifier;
 use rustc_session::cstore::{CrateSource, ExternCrate};
 use rustc_span::hygiene::HygieneDecodeContext;
 use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext, kw};
@@ -73,6 +74,9 @@ impl MetadataBlob {
 /// own crate numbers.
 pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
 
+/// Target modifiers - abi or exploit mitigations flags
+pub(crate) type TargetModifiers = Vec<TargetModifier>;
+
 pub(crate) struct CrateMetadata {
     /// The primary crate data - binary metadata blob.
     blob: MetadataBlob,
@@ -961,6 +965,13 @@ impl CrateRoot {
     ) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
         self.crate_deps.decode(metadata)
     }
+
+    pub(crate) fn decode_target_modifiers<'a>(
+        &self,
+        metadata: &'a MetadataBlob,
+    ) -> impl ExactSizeIterator<Item = TargetModifier> + Captures<'a> {
+        self.target_modifiers.decode(metadata)
+    }
 }
 
 impl<'a> CrateMetadataRef<'a> {
@@ -1883,6 +1894,10 @@ impl CrateMetadata {
         self.dependencies.push(cnum);
     }
 
+    pub(crate) fn target_modifiers(&self) -> TargetModifiers {
+        self.root.decode_target_modifiers(&self.blob).collect()
+    }
+
     pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
         let update =
             Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index da07ad8f6c0..028ff56155f 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -165,7 +165,7 @@ macro_rules! provide_one {
             // doesn't need to do this (and can't, as it would cause a query cycle).
             use rustc_middle::dep_graph::dep_kinds;
             if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() {
-                $tcx.ensure().crate_hash($def_id.krate);
+                $tcx.ensure_ok().crate_hash($def_id.krate);
             }
 
             let cdata = rustc_data_structures::sync::FreezeReadGuard::map(CStore::from_tcx($tcx), |c| {
@@ -689,7 +689,7 @@ fn provide_cstore_hooks(providers: &mut Providers) {
     providers.hooks.def_path_hash_to_def_id_extern = |tcx, hash, stable_crate_id| {
         // If this is a DefPathHash from an upstream crate, let the CrateStore map
         // it to a DefId.
-        let cstore = CStore::from_tcx(tcx.tcx);
+        let cstore = CStore::from_tcx(tcx);
         let cnum = *tcx
             .untracked()
             .stable_crate_ids
@@ -702,11 +702,11 @@ fn provide_cstore_hooks(providers: &mut Providers) {
     };
 
     providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| {
-        let cstore = CStore::from_tcx(tcx.tcx);
+        let cstore = CStore::from_tcx(tcx);
         cstore.get_crate_data(cnum).expn_hash_to_expn_id(tcx.sess, index_guess, hash)
     };
     providers.hooks.import_source_files = |tcx, cnum| {
-        let cstore = CStore::from_tcx(tcx.tcx);
+        let cstore = CStore::from_tcx(tcx);
         let cdata = cstore.get_crate_data(cnum);
         for file_index in 0..cdata.root.source_map.size() {
             cdata.imported_source_file(file_index as u32, tcx.sess);
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 904409dd777..db41a33dcc5 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -9,6 +9,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::memmap::{Mmap, MmapMut};
 use rustc_data_structures::sync::{Lrc, join, par_for_each_in};
 use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_data_structures::thousands::format_with_underscores;
 use rustc_feature::Features;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet};
@@ -22,10 +23,9 @@ use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::fast_reject::{self, TreatParams};
 use rustc_middle::ty::{AssocItemContainer, SymbolName};
-use rustc_middle::util::common::to_readable_str;
 use rustc_middle::{bug, span_bug};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque};
-use rustc_session::config::{CrateType, OptLevel};
+use rustc_session::config::{CrateType, OptLevel, TargetModifier};
 use rustc_span::hygiene::HygieneEncodeContext;
 use rustc_span::{
     ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext,
@@ -692,6 +692,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         // Encode source_map. This needs to be done last, because encoding `Span`s tells us which
         // `SourceFiles` we actually need to encode.
         let source_map = stat!("source-map", || self.encode_source_map());
+        let target_modifiers = stat!("target-modifiers", || self.encode_target_modifiers());
 
         let root = stat!("final", || {
             let attrs = tcx.hir().krate_attrs();
@@ -735,6 +736,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 native_libraries,
                 foreign_modules,
                 source_map,
+                target_modifiers,
                 traits,
                 impls,
                 incoherent_impls,
@@ -782,7 +784,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     "{} {:<23}{:>10} ({:4.1}%)",
                     prefix,
                     label,
-                    to_readable_str(size),
+                    format_with_underscores(size),
                     perc(size)
                 );
             }
@@ -791,7 +793,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 "{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
                 prefix,
                 "Total",
-                to_readable_str(total_bytes),
+                format_with_underscores(total_bytes),
                 perc(zero_bytes)
             );
             eprintln!("{prefix}");
@@ -2009,6 +2011,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy_array(deps.iter().map(|(_, dep)| dep))
     }
 
+    fn encode_target_modifiers(&mut self) -> LazyArray<TargetModifier> {
+        empty_proc_macro!(self);
+        let tcx = self.tcx;
+        self.lazy_array(tcx.sess.opts.gather_target_modifiers())
+    }
+
     fn encode_lib_features(&mut self) -> LazyArray<(Symbol, FeatureStability)> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
@@ -2191,13 +2199,13 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
         let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
 
         if encode_const {
-            tcx.ensure_with_value().mir_for_ctfe(def_id);
+            tcx.ensure_done().mir_for_ctfe(def_id);
         }
         if encode_opt {
-            tcx.ensure_with_value().optimized_mir(def_id);
+            tcx.ensure_done().optimized_mir(def_id);
         }
         if encode_opt || encode_const {
-            tcx.ensure_with_value().promoted_mir(def_id);
+            tcx.ensure_done().promoted_mir(def_id);
         }
     })
 }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index d1d356c5220..7b34e605c53 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,7 +1,7 @@
 use std::marker::PhantomData;
 use std::num::NonZero;
 
-pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
+pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob, TargetModifiers};
 use decoder::{DecodeContext, Metadata};
 use def_path_hash_map::DefPathHashMapRef;
 use encoder::EncodeContext;
@@ -32,7 +32,7 @@ use rustc_middle::ty::{
 use rustc_middle::util::Providers;
 use rustc_middle::{mir, trivially_parameterized_over_tcx};
 use rustc_serialize::opaque::FileEncoder;
-use rustc_session::config::SymbolManglingVersion;
+use rustc_session::config::{SymbolManglingVersion, TargetModifier};
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
@@ -282,6 +282,7 @@ pub(crate) struct CrateRoot {
     def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>,
 
     source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>,
+    target_modifiers: LazyArray<TargetModifier>,
 
     compiler_builtins: bool,
     needs_allocator: bool,
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 8dc529b4d7a..ded1c580572 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -17,6 +17,9 @@ middle_assert_gen_resume_after_panic = `gen` fn or block cannot be further itera
 middle_assert_misaligned_ptr_deref =
     misaligned pointer dereference: address must be a multiple of {$required} but is {$found}
 
+middle_assert_null_ptr_deref =
+    null pointer dereference occurred
+
 middle_assert_op_overflow =
     attempt to compute `{$left} {$op} {$right}`, which would overflow
 
@@ -32,6 +35,8 @@ middle_assert_shl_overflow =
 middle_assert_shr_overflow =
     attempt to shift right by `{$val}`, which would overflow
 
+middle_autodiff_unsafe_inner_const_ref = reading from a `Duplicated` const {$ty} is unsafe
+
 middle_bounds_check =
     index out of bounds: the length is {$len} but the index is {$index}
 
@@ -107,6 +112,8 @@ middle_type_length_limit = reached the type-length limit while instantiating `{$
 middle_unknown_layout =
     the type `{$ty}` has an unknown layout
 
+middle_unsupported_union = we don't support unions yet: '{$ty_name}'
+
 middle_values_too_big =
     values of the type `{$ty}` are too big for the target architecture
 
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 750531b638e..eaccd8c360e 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -87,6 +87,7 @@ macro_rules! arena_types {
             [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>,
             [decode] attribute: rustc_hir::Attribute,
             [] name_set: rustc_data_structures::unord::UnordSet<rustc_span::Symbol>,
+            [] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem,
             [] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>,
             [] pats: rustc_middle::ty::PatternKind<'tcx>,
 
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index b0187a1848c..b30d3a950c6 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -37,6 +37,20 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> {
     pub sub: TypeMismatchReason,
 }
 
+#[derive(Diagnostic)]
+#[diag(middle_unsupported_union)]
+pub struct UnsupportedUnion {
+    pub ty_name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(middle_autodiff_unsafe_inner_const_ref)]
+pub struct AutodiffUnsafeInnerConstRef {
+    #[primary_span]
+    pub span: Span,
+    pub ty: String,
+}
+
 #[derive(Subdiagnostic)]
 pub enum TypeMismatchReason {
     #[label(middle_conflict_types)]
diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs
index 92fa64b0987..276a02b4e0f 100644
--- a/compiler/rustc_middle/src/hooks/mod.rs
+++ b/compiler/rustc_middle/src/hooks/mod.rs
@@ -1,16 +1,14 @@
-//! "Hooks" provide a way for `tcx` functionality to be provided by some downstream crate without
-//! everything in rustc having to depend on that crate. This is somewhat similar to queries, but
-//! queries come with a lot of machinery for caching and incremental compilation, whereas hooks are
-//! just plain function pointers without any of the query magic.
+//! "Hooks" let you write `tcx` methods in downstream crates and call them in this crate, reducing
+//! the amount of code that needs to be in this crate (which is already very big). This is somewhat
+//! similar to queries, but queries come with a lot of machinery for caching and incremental
+//! compilation, whereas hooks are just plain function pointers without any of the query magic.
 
 use rustc_hir::def_id::{DefId, DefPathHash};
 use rustc_session::StableCrateId;
 use rustc_span::def_id::{CrateNum, LocalDefId};
-use rustc_span::{DUMMY_SP, ExpnHash, ExpnId};
-use tracing::instrument;
+use rustc_span::{ExpnHash, ExpnId};
 
 use crate::mir;
-use crate::query::TyCtxtAt;
 use crate::ty::{Ty, TyCtxt};
 
 macro_rules! declare_hooks {
@@ -22,26 +20,14 @@ macro_rules! declare_hooks {
             #[inline(always)]
             pub fn $name(self, $($arg: $K,)*) -> $V
             {
-                self.at(DUMMY_SP).$name($($arg,)*)
-            }
-            )*
-        }
-
-        impl<'tcx> TyCtxtAt<'tcx> {
-            $(
-            $(#[$attr])*
-            #[inline(always)]
-            #[instrument(level = "debug", skip(self), ret)]
-            pub fn $name(self, $($arg: $K,)*) -> $V
-            {
-                (self.tcx.hooks.$name)(self, $($arg,)*)
+                (self.hooks.$name)(self, $($arg,)*)
             }
             )*
         }
 
         pub struct Providers {
             $(pub $name: for<'tcx> fn(
-                TyCtxtAt<'tcx>,
+                TyCtxt<'tcx>,
                 $($arg: $K,)*
             ) -> $V,)*
         }
@@ -75,12 +61,6 @@ declare_hooks! {
     /// (Eligible functions might nevertheless be skipped for other reasons.)
     hook is_eligible_for_coverage(key: LocalDefId) -> bool;
 
-    /// Create the MIR for a given `DefId` - this includes
-    /// unreachable code.
-    /// You do not want to call this yourself, instead use the cached version
-    /// via `mir_built`
-    hook build_mir(key: LocalDefId) -> mir::Body<'tcx>;
-
     /// Imports all `SourceFile`s from the given crate into the current session.
     /// This normally happens automatically when we decode a `Span` from
     /// that crate's metadata - however, the incr comp cache needs
@@ -99,14 +79,11 @@ declare_hooks! {
     /// Will fetch a DefId from a DefPathHash for a foreign crate.
     hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId;
 
-    /// Create a THIR tree for debugging.
-    hook thir_tree(key: LocalDefId) -> String;
-
-    /// Create a list-like THIR representation for debugging.
-    hook thir_flat(key: LocalDefId) -> String;
-
     /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
     /// can just link to the upstream crate and therefore don't need a mono item.
+    ///
+    /// Note: this hook isn't called within `rustc_middle` but #127779 suggests it's a hook instead
+    /// of a normal function because external tools might want to override it.
     hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool;
 
     hook alloc_self_profile_query_strings() -> ();
diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs
index 3dfcf90cb93..73e8971c3bd 100644
--- a/compiler/rustc_middle/src/infer/mod.rs
+++ b/compiler/rustc_middle/src/infer/mod.rs
@@ -1,2 +1 @@
 pub mod canonical;
-pub mod unify_key;
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index cae980cde61..ab711aca573 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -8,8 +8,7 @@ use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_session::Session;
 use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
 use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId};
-use rustc_span::hygiene::{ExpnKind, MacroKind};
-use rustc_span::{DUMMY_SP, DesugaringKind, Span, Symbol, kw};
+use rustc_span::{DUMMY_SP, Span, Symbol, kw};
 use tracing::instrument;
 
 use crate::ty::TyCtxt;
@@ -201,7 +200,7 @@ impl LintExpectation {
     }
 }
 
-pub fn explain_lint_level_source(
+fn explain_lint_level_source(
     lint: &'static Lint,
     level: Level,
     src: LintLevelSource,
@@ -325,7 +324,7 @@ pub fn lint_level(
         // If this code originates in a foreign macro, aka something that this crate
         // did not itself author, then it's likely that there's nothing this crate
         // can do about it. We probably want to skip the lint entirely.
-        if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
+        if err.span.primary_spans().iter().any(|s| s.in_external_macro(sess.source_map())) {
             // Any suggestions made here are likely to be incorrect, so anything we
             // emit shouldn't be automatically fixed by rustfix.
             err.disable_suggestions();
@@ -422,36 +421,3 @@ pub fn lint_level(
     }
     lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
 }
-
-/// Returns whether `span` originates in a foreign crate's external macro.
-///
-/// This is used to test whether a lint should not even begin to figure out whether it should
-/// be reported on the current node.
-pub fn in_external_macro(sess: &Session, span: Span) -> bool {
-    let expn_data = span.ctxt().outer_expn_data();
-    match expn_data.kind {
-        ExpnKind::Root
-        | ExpnKind::Desugaring(
-            DesugaringKind::ForLoop
-            | DesugaringKind::WhileLoop
-            | DesugaringKind::OpaqueTy
-            | DesugaringKind::Async
-            | DesugaringKind::Await,
-        ) => false,
-        ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
-        ExpnKind::Macro(MacroKind::Bang, _) => {
-            // Dummy span for the `def_site` means it's an external macro.
-            expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
-        }
-        ExpnKind::Macro { .. } => true, // definitely a plugin
-    }
-}
-
-/// Return whether `span` is generated by `async` or `await`.
-pub fn is_from_async_await(span: Span) -> bool {
-    let expn_data = span.ctxt().outer_expn_data();
-    match expn_data.kind {
-        ExpnKind::Desugaring(DesugaringKind::Async | DesugaringKind::Await) => true,
-        _ => false,
-    }
-}
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 39816c17b98..b3064d8fe25 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -4,8 +4,8 @@
 ///
 /// If you have a span available, you should use [`span_bug`] instead.
 ///
-/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`]
-/// may be useful.
+/// If the bug should only be emitted when compilation didn't fail,
+/// [`DiagCtxtHandle::span_delayed_bug`] may be useful.
 ///
 /// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug
 /// [`span_bug`]: crate::span_bug
@@ -14,14 +14,8 @@ macro_rules! bug {
     () => (
         $crate::bug!("impossible case reached")
     );
-    ($msg:expr) => (
-        $crate::util::bug::bug_fmt(::std::format_args!($msg))
-    );
-    ($msg:expr,) => (
-        $crate::bug!($msg)
-    );
-    ($fmt:expr, $($arg:tt)+) => (
-        $crate::util::bug::bug_fmt(::std::format_args!($fmt, $($arg)+))
+    ($($arg:tt)+) => (
+        $crate::util::bug::bug_fmt(::std::format_args!($($arg)+))
     );
 }
 
@@ -30,20 +24,14 @@ macro_rules! bug {
 /// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger
 /// ICEs.
 ///
-/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`]
-/// may be useful.
+/// If the bug should only be emitted when compilation didn't fail,
+/// [`DiagCtxtHandle::span_delayed_bug`] may be useful.
 ///
 /// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug
 #[macro_export]
 macro_rules! span_bug {
-    ($span:expr, $msg:expr) => (
-        $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg))
-    );
-    ($span:expr, $msg:expr,) => (
-        $crate::span_bug!($span, $msg)
-    );
-    ($span:expr, $fmt:expr, $($arg:tt)+) => (
-        $crate::util::bug::span_bug_fmt($span, ::std::format_args!($fmt, $($arg)+))
+    ($span:expr, $($arg:tt)+) => (
+        $crate::util::bug::span_bug_fmt($span, ::std::format_args!($($arg)+))
     );
 }
 
@@ -53,7 +41,6 @@ macro_rules! span_bug {
 // When possible, use one of these (relatively) convenient macros to write
 // the impls for you.
 
-#[macro_export]
 macro_rules! TrivialLiftImpls {
     ($($ty:ty),+ $(,)?) => {
         $(
@@ -69,7 +56,6 @@ macro_rules! TrivialLiftImpls {
 
 /// Used for types that are `Copy` and which **do not care about arena
 /// allocated data** (i.e., don't need to be folded).
-#[macro_export]
 macro_rules! TrivialTypeTraversalImpls {
     ($($ty:ty),+ $(,)?) => {
         $(
@@ -104,7 +90,6 @@ macro_rules! TrivialTypeTraversalImpls {
     };
 }
 
-#[macro_export]
 macro_rules! TrivialTypeTraversalAndLiftImpls {
     ($($t:tt)*) => {
         TrivialTypeTraversalImpls! { $($t)* }
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index cc980f6e62a..1784665bcae 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -1,4 +1,5 @@
 use rustc_abi::Align;
+use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs;
 use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::Symbol;
@@ -52,6 +53,8 @@ pub struct CodegenFnAttrs {
     /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
     /// the function entry.
     pub patchable_function_entry: Option<PatchableFunctionEntry>,
+    /// For the `#[autodiff]` macros.
+    pub autodiff_item: Option<AutoDiffAttrs>,
 }
 
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -160,6 +163,7 @@ impl CodegenFnAttrs {
             instruction_set: None,
             alignment: None,
             patchable_function_entry: None,
+            autodiff_item: None,
         }
     }
 
diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
index 111ac990bc7..51a079e8bc1 100644
--- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
+++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
@@ -45,15 +45,22 @@ pub enum ObjectLifetimeDefault {
     Param(DefId),
 }
 
-/// Maps the id of each lifetime reference to the lifetime decl
+/// Maps the id of each bound variable reference to the variable decl
 /// that it corresponds to.
-#[derive(HashStable, Debug)]
+#[derive(Debug, Default, HashStable)]
 pub struct ResolveBoundVars {
-    /// Maps from every use of a named (not anonymous) lifetime to a
-    /// `Region` describing how that region is bound
+    // Maps from every use of a named (not anonymous) bound var to a
+    // `ResolvedArg` describing how that variable is bound.
     pub defs: SortedMap<ItemLocalId, ResolvedArg>,
 
+    // Maps relevant hir items to the bound vars on them. These include:
+    // - function defs
+    // - function pointers
+    // - closures
+    // - trait refs
+    // - bound types (like `T` in `for<'a> T<'a>: Foo`)
     pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>,
 
+    // List captured variables for each opaque type.
     pub opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>,
 }
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 66d97fda433..923160cc0cc 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -250,7 +250,7 @@ impl<'tcx> Const<'tcx> {
                     // Dont use the outer ty as on invalid code we can wind up with them not being the same.
                     // this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir
                     // was originally `({N: usize} + 1_usize)` under `generic_const_exprs`.
-                    ty::ConstKind::Value(ty, _) => ty,
+                    ty::ConstKind::Value(cv) => cv.ty,
                     _ => *ty,
                 }
             }
@@ -264,7 +264,7 @@ impl<'tcx> Const<'tcx> {
     pub fn is_required_const(&self) -> bool {
         match self {
             Const::Ty(_, c) => match c.kind() {
-                ty::ConstKind::Value(_, _) => false, // already a value, cannot error
+                ty::ConstKind::Value(_) => false, // already a value, cannot error
                 _ => true,
             },
             Const::Val(..) => false, // already a value, cannot error
@@ -276,11 +276,11 @@ impl<'tcx> Const<'tcx> {
     pub fn try_to_scalar(self) -> Option<Scalar> {
         match self {
             Const::Ty(_, c) => match c.kind() {
-                ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => {
+                ty::ConstKind::Value(cv) if cv.ty.is_primitive() => {
                     // A valtree of a type where leaves directly represent the scalar const value.
                     // Just checking whether it is a leaf is insufficient as e.g. references are leafs
                     // but the leaf value is the value they point to, not the reference itself!
-                    Some(valtree.unwrap_leaf().into())
+                    Some(cv.valtree.unwrap_leaf().into())
                 }
                 _ => None,
             },
@@ -295,9 +295,7 @@ impl<'tcx> Const<'tcx> {
         match self {
             Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x),
             Const::Ty(_, c) => match c.kind() {
-                ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => {
-                    Some(valtree.unwrap_leaf())
-                }
+                ty::ConstKind::Value(cv) if cv.ty.is_primitive() => Some(cv.valtree.unwrap_leaf()),
                 _ => None,
             },
             _ => None,
@@ -328,7 +326,7 @@ impl<'tcx> Const<'tcx> {
                 }
 
                 match c.kind() {
-                    ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))),
+                    ConstKind::Value(cv) => Ok(tcx.valtree_to_const_val(cv)),
                     ConstKind::Expr(_) => {
                         bug!("Normalization of `ty::ConstKind::Expr` is unimplemented")
                     }
@@ -353,13 +351,13 @@ impl<'tcx> Const<'tcx> {
         typing_env: ty::TypingEnv<'tcx>,
     ) -> Option<Scalar> {
         if let Const::Ty(_, c) = self
-            && let ty::ConstKind::Value(ty, val) = c.kind()
-            && ty.is_primitive()
+            && let ty::ConstKind::Value(cv) = c.kind()
+            && cv.ty.is_primitive()
         {
             // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that
             // are valtree leaves, and *not* on references. (References should return the
             // pointer here, which valtrees don't represent.)
-            Some(val.unwrap_leaf().into())
+            Some(cv.valtree.unwrap_leaf().into())
         } else {
             self.eval(tcx, typing_env, DUMMY_SP).ok()?.try_to_scalar()
         }
@@ -473,7 +471,7 @@ impl<'tcx> Const<'tcx> {
                 // A valtree may be a reference. Valtree references correspond to a
                 // different allocation each time they are evaluated. Valtrees for primitive
                 // types are fine though.
-                ty::ConstKind::Value(ty, _) => ty.is_primitive(),
+                ty::ConstKind::Value(cv) => cv.ty.is_primitive(),
                 ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false,
                 // This can happen if evaluation of a constant failed. The result does not matter
                 // much since compilation is doomed.
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 1b07846e0cf..2e4d258ffff 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -270,6 +270,12 @@ impl AllocRange {
     }
 }
 
+/// Whether a new allocation should be initialized with zero-bytes.
+pub enum AllocInit {
+    Uninit,
+    Zero,
+}
+
 // The constructors are all without extra; the extra gets added by a machine hook later.
 impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
     /// Creates an allocation initialized by the given bytes
@@ -294,7 +300,12 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
         Allocation::from_bytes(slice, Align::ONE, Mutability::Not)
     }
 
-    fn uninit_inner<R>(size: Size, align: Align, fail: impl FnOnce() -> R) -> Result<Self, R> {
+    fn new_inner<R>(
+        size: Size,
+        align: Align,
+        init: AllocInit,
+        fail: impl FnOnce() -> R,
+    ) -> Result<Self, R> {
         // We raise an error if we cannot create the allocation on the host.
         // This results in an error that can happen non-deterministically, since the memory
         // available to the compiler can change between runs. Normally queries are always
@@ -306,7 +317,10 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
         Ok(Allocation {
             bytes,
             provenance: ProvenanceMap::new(),
-            init_mask: InitMask::new(size, false),
+            init_mask: InitMask::new(size, match init {
+                AllocInit::Uninit => false,
+                AllocInit::Zero => true,
+            }),
             align,
             mutability: Mutability::Mut,
             extra: (),
@@ -315,8 +329,8 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
 
     /// Try to create an Allocation of `size` bytes, failing if there is not enough memory
     /// available to the compiler to do so.
-    pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> {
-        Self::uninit_inner(size, align, || {
+    pub fn try_new<'tcx>(size: Size, align: Align, init: AllocInit) -> InterpResult<'tcx, Self> {
+        Self::new_inner(size, align, init, || {
             ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation"));
             InterpErrorKind::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
         })
@@ -328,8 +342,8 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
     ///
     /// Example use case: To obtain an Allocation filled with specific data,
     /// first call this function and then call write_scalar to fill in the right data.
-    pub fn uninit(size: Size, align: Align) -> Self {
-        match Self::uninit_inner(size, align, || {
+    pub fn new(size: Size, align: Align, init: AllocInit) -> Self {
+        match Self::new_inner(size, align, init, || {
             panic!(
                 "interpreter ran out of memory: cannot create allocation of {} bytes",
                 size.bytes()
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index b88137544bc..f4f9f221a75 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -30,8 +30,8 @@ pub use {
 };
 
 pub use self::allocation::{
-    AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk,
-    InitChunkIter, alloc_range,
+    AllocBytes, AllocError, AllocInit, AllocRange, AllocResult, Allocation, ConstAllocation,
+    InitChunk, InitChunkIter, alloc_range,
 };
 pub use self::error::{
     BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult,
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 4c47d9636d3..78749428c6d 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -9,7 +9,7 @@ use super::{
     ReportedErrorInfo,
 };
 use crate::mir;
-use crate::query::TyCtxtEnsure;
+use crate::query::TyCtxtEnsureOk;
 use crate::ty::visit::TypeVisitableExt;
 use crate::ty::{self, GenericArgs, TyCtxt};
 
@@ -198,7 +198,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-impl<'tcx> TyCtxtEnsure<'tcx> {
+impl<'tcx> TyCtxtEnsureOk<'tcx> {
     /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
     /// that can't take any generic arguments like const items or enum discriminants. If a
     /// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 0f3fca434ee..cfb78e5dddf 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -27,7 +27,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
 use rustc_serialize::{Decodable, Encodable};
 use rustc_span::source_map::Spanned;
 use rustc_span::{DUMMY_SP, Span, Symbol};
-use tracing::trace;
+use tracing::{debug, trace};
 
 pub use self::query::*;
 use self::visit::TyContext;
@@ -1796,6 +1796,47 @@ impl DefLocation {
     }
 }
 
+/// Checks if the specified `local` is used as the `self` parameter of a method call
+/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
+/// returned.
+pub fn find_self_call<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    local: Local,
+    block: BasicBlock,
+) -> Option<(DefId, GenericArgsRef<'tcx>)> {
+    debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator);
+    if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
+        &body[block].terminator
+        && let Operand::Constant(box ConstOperand { const_, .. }) = func
+        && let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
+        && let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
+            tcx.opt_associated_item(def_id)
+        && let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
+            **args
+    {
+        if self_place.as_local() == Some(local) {
+            return Some((def_id, fn_args));
+        }
+
+        // Handle the case where `self_place` gets reborrowed.
+        // This happens when the receiver is `&T`.
+        for stmt in &body[block].statements {
+            if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
+                && let Some(reborrow_local) = place.as_local()
+                && self_place.as_local() == Some(reborrow_local)
+                && let Rvalue::Ref(_, _, deref_place) = rvalue
+                && let PlaceRef { local: deref_local, projection: [ProjectionElem::Deref] } =
+                    deref_place.as_ref()
+                && deref_local == local
+            {
+                return Some((def_id, fn_args));
+            }
+        }
+    }
+    None
+}
+
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
 mod size_asserts {
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 6fa3fa2432d..75931956310 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -1,6 +1,7 @@
 use std::fmt;
 use std::hash::Hash;
 
+use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_attr_parsing::InlineAttr;
 use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN};
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -91,51 +92,88 @@ impl<'tcx> MonoItem<'tcx> {
     }
 
     pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
-        let generate_cgu_internal_copies =
-            (tcx.sess.opts.optimize != OptLevel::No) && !tcx.sess.link_dead_code();
+        // The case handling here is written in the same style as cross_crate_inlinable, we first
+        // handle the cases where we must use a particular instantiation mode, then cascade down
+        // through a sequence of heuristics.
 
-        match *self {
-            MonoItem::Fn(ref instance) => {
-                let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id);
-                // If this function isn't inlined or otherwise has an extern
-                // indicator, then we'll be creating a globally shared version.
-                let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
-                if codegen_fn_attrs.contains_extern_indicator()
-                    || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
-                    || !instance.def.generates_cgu_internal_copy(tcx)
-                    || Some(instance.def_id()) == entry_def_id
-                {
-                    return InstantiationMode::GloballyShared { may_conflict: false };
-                }
-
-                if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
-                    && self.is_generic_fn()
-                {
-                    // Upgrade inline(never) to a globally shared instance.
-                    return InstantiationMode::GloballyShared { may_conflict: true };
-                }
-
-                // At this point we don't have explicit linkage and we're an
-                // inlined function. If this crate's build settings permit,
-                // we'll be creating a local copy per CGU.
-                if generate_cgu_internal_copies {
-                    return InstantiationMode::LocalCopy;
-                }
-
-                // Finally, if this is `#[inline(always)]` we're sure to respect
-                // that with an inline copy per CGU, but otherwise we'll be
-                // creating one copy of this `#[inline]` function which may
-                // conflict with upstream crates as it could be an exported
-                // symbol.
-                if tcx.codegen_fn_attrs(instance.def_id()).inline.always() {
-                    InstantiationMode::LocalCopy
-                } else {
-                    InstantiationMode::GloballyShared { may_conflict: true }
-                }
-            }
+        // The first thing we do is detect MonoItems which we must instantiate exactly once in the
+        // whole program.
+
+        // Statics and global_asm! must be instantiated exactly once.
+        let instance = match *self {
+            MonoItem::Fn(instance) => instance,
             MonoItem::Static(..) | MonoItem::GlobalAsm(..) => {
-                InstantiationMode::GloballyShared { may_conflict: false }
+                return InstantiationMode::GloballyShared { may_conflict: false };
             }
+        };
+
+        // Similarly, the executable entrypoint must be instantiated exactly once.
+        if let Some((entry_def_id, _)) = tcx.entry_fn(()) {
+            if instance.def_id() == entry_def_id {
+                return InstantiationMode::GloballyShared { may_conflict: false };
+            }
+        }
+
+        // If the function is #[naked] or contains any other attribute that requires exactly-once
+        // instantiation:
+        let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
+        if codegen_fn_attrs.contains_extern_indicator()
+            || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
+        {
+            return InstantiationMode::GloballyShared { may_conflict: false };
+        }
+
+        // FIXME: The logic for which functions are permitted to get LocalCopy is actually spread
+        // across 4 functions:
+        // * cross_crate_inlinable(def_id)
+        // * InstanceKind::requires_inline
+        // * InstanceKind::generate_cgu_internal_copy
+        // * MonoItem::instantiation_mode
+        // Since reachable_non_generics calls InstanceKind::generates_cgu_internal_copy to decide
+        // which symbols this crate exports, we are obligated to only generate LocalCopy when
+        // generates_cgu_internal_copy returns true.
+        if !instance.def.generates_cgu_internal_copy(tcx) {
+            return InstantiationMode::GloballyShared { may_conflict: false };
+        }
+
+        // Beginning of heuristics. The handling of link-dead-code and inline(always) are QoL only,
+        // the compiler should not crash and linkage should work, but codegen may be undesirable.
+
+        // -Clink-dead-code was given an unfortunate name; the point of the flag is to assist
+        // coverage tools which rely on having every function in the program appear in the
+        // generated code. If we select LocalCopy, functions which are not used because they are
+        // missing test coverage will disappear from such coverage reports, defeating the point.
+        // Note that -Cinstrument-coverage does not require such assistance from us, only coverage
+        // tools implemented without compiler support ironically require a special compiler flag.
+        if tcx.sess.link_dead_code() {
+            return InstantiationMode::GloballyShared { may_conflict: true };
+        }
+
+        // To ensure that #[inline(always)] can be inlined as much as possible, especially in unoptimized
+        // builds, we always select LocalCopy.
+        if codegen_fn_attrs.inline.always() {
+            return InstantiationMode::LocalCopy;
+        }
+
+        // #[inline(never)] functions in general are poor candidates for inlining and thus since
+        // LocalCopy generally increases code size for the benefit of optimizations from inlining,
+        // we want to give them GloballyShared codegen.
+        // The slight problem is that generic functions need to always support cross-crate
+        // compilation, so all previous stages of the compiler are obligated to treat generic
+        // functions the same as those that unconditionally get LocalCopy codegen. It's only when
+        // we get here that we can at least not codegen a #[inline(never)] generic function in all
+        // of our CGUs.
+        if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
+            && self.is_generic_fn()
+        {
+            return InstantiationMode::GloballyShared { may_conflict: true };
+        }
+
+        // The fallthrough case is to generate LocalCopy for all optimized builds, and
+        // GloballyShared with conflict prevention when optimizations are disabled.
+        match tcx.sess.opts.optimize {
+            OptLevel::No => InstantiationMode::GloballyShared { may_conflict: true },
+            _ => InstantiationMode::LocalCopy,
         }
     }
 
@@ -246,6 +284,7 @@ impl ToStableHashKey<StableHashingContext<'_>> for MonoItem<'_> {
 pub struct MonoItemPartitions<'tcx> {
     pub codegen_units: &'tcx [CodegenUnit<'tcx>],
     pub all_mono_items: &'tcx DefIdSet,
+    pub autodiff_items: &'tcx [AutoDiffItem],
 }
 
 #[derive(Debug, HashStable)]
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 3b4fba97e60..09d7e60e199 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1248,6 +1248,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             ShallowInitBox(ref place, ref ty) => {
                 with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
             }
+
+            WrapUnsafeBinder(ref op, ty) => {
+                with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
+            }
         }
     }
 }
@@ -1308,6 +1312,9 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
             ProjectionElem::Index(_)
             | ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Subslice { .. } => {}
+            ProjectionElem::UnwrapUnsafeBinder(_) => {
+                write!(fmt, "unwrap_binder!(")?;
+            }
         }
     }
 
@@ -1356,6 +1363,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
             ProjectionElem::Subslice { from, to, from_end: false } => {
                 write!(fmt, "[{from:?}..{to:?}]")?;
             }
+            ProjectionElem::UnwrapUnsafeBinder(ty) => {
+                write!(fmt, "; {ty})")?;
+            }
         }
     }
 
@@ -1441,7 +1451,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
                     ty::ConstKind::Unevaluated(uv) => {
                         format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
                     }
-                    ty::ConstKind::Value(_, val) => format!("ty::Valtree({})", fmt_valtree(&val)),
+                    ty::ConstKind::Value(cv) => {
+                        format!("ty::Valtree({})", fmt_valtree(&cv.valtree))
+                    }
                     // No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`.
                     ty::ConstKind::Error(_) => "Error".to_string(),
                     // These variants shouldn't exist in the MIR.
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 609d5647d04..d345c99f902 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -62,7 +62,8 @@ impl<V, T> ProjectionElem<V, T> {
             | Self::Subtype(_)
             | Self::ConstantIndex { .. }
             | Self::Subslice { .. }
-            | Self::Downcast(_, _) => false,
+            | Self::Downcast(_, _)
+            | Self::UnwrapUnsafeBinder(..) => false,
         }
     }
 
@@ -76,7 +77,8 @@ impl<V, T> ProjectionElem<V, T> {
             | Self::Subtype(_)
             | Self::ConstantIndex { .. }
             | Self::Subslice { .. }
-            | Self::Downcast(_, _) => true,
+            | Self::Downcast(_, _)
+            | Self::UnwrapUnsafeBinder(..) => true,
         }
     }
 
@@ -102,6 +104,9 @@ impl<V, T> ProjectionElem<V, T> {
             | Self::Subtype(_)
             | Self::OpaqueCast(_)
             | Self::Subslice { .. } => false,
+
+            // FIXME(unsafe_binders): Figure this out.
+            Self::UnwrapUnsafeBinder(..) => false,
         }
     }
 }
@@ -443,7 +448,8 @@ impl<'tcx> Rvalue<'tcx> {
             | Rvalue::UnaryOp(_, _)
             | Rvalue::Discriminant(_)
             | Rvalue::Aggregate(_, _)
-            | Rvalue::ShallowInitBox(_, _) => true,
+            | Rvalue::ShallowInitBox(_, _)
+            | Rvalue::WrapUnsafeBinder(_, _) => true,
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 5868b64f6b5..2da25f480c6 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1076,6 +1076,7 @@ pub enum AssertKind<O> {
     ResumedAfterReturn(CoroutineKind),
     ResumedAfterPanic(CoroutineKind),
     MisalignedPointerDereference { required: O, found: O },
+    NullPointerDereference,
 }
 
 #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
@@ -1275,6 +1276,10 @@ pub enum ProjectionElem<V, T> {
     /// requiring an intermediate variable.
     OpaqueCast(T),
 
+    /// A transmute from an unsafe binder to the type that it wraps. This is a projection
+    /// of a place, so it doesn't necessarily constitute a move out of the binder.
+    UnwrapUnsafeBinder(T),
+
     /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
     /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
     /// explicit during optimizations and codegen.
@@ -1492,6 +1497,9 @@ pub enum Rvalue<'tcx> {
     /// optimizations and codegen backends that previously had to handle deref operations anywhere
     /// in a place.
     CopyForDeref(Place<'tcx>),
+
+    /// Wraps a value in an unsafe binder.
+    WrapUnsafeBinder(Operand<'tcx>, Ty<'tcx>),
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 4d11492e94d..49449426fa4 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -146,6 +146,11 @@ impl<'tcx> PlaceTy<'tcx> {
             ProjectionElem::Subtype(ty) => {
                 PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
             }
+
+            // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
+            ProjectionElem::UnwrapUnsafeBinder(ty) => {
+                PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
+            }
         };
         debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
         answer
@@ -241,6 +246,7 @@ impl<'tcx> Rvalue<'tcx> {
             },
             Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
             Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
+            Rvalue::WrapUnsafeBinder(_, ty) => ty,
         }
     }
 
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index c04a8251fbc..2fe116212eb 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -206,6 +206,7 @@ impl<O> AssertKind<O> {
             ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
                 LangItem::PanicGenFnNonePanic
             }
+            NullPointerDereference => LangItem::PanicNullPointerDereference,
 
             BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
                 bug!("Unexpected AssertKind")
@@ -271,6 +272,7 @@ impl<O> AssertKind<O> {
                     "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
                 )
             }
+            NullPointerDereference => write!(f, "\"null pointer dereference occured\""),
             ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
                 write!(f, "\"coroutine resumed after completion\"")
             }
@@ -341,7 +343,7 @@ impl<O> AssertKind<O> {
             ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
                 middle_assert_coroutine_resume_after_panic
             }
-
+            NullPointerDereference => middle_assert_null_ptr_deref,
             MisalignedPointerDereference { .. } => middle_assert_misaligned_ptr_deref,
         }
     }
@@ -374,7 +376,7 @@ impl<O> AssertKind<O> {
                 add!("left", format!("{left:#?}"));
                 add!("right", format!("{right:#?}"));
             }
-            ResumedAfterReturn(_) | ResumedAfterPanic(_) => {}
+            ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => {}
             MisalignedPointerDereference { required, found } => {
                 add!("required", format!("{required:#?}"));
                 add!("found", format!("{found:#?}"));
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index b59b9e55fe8..9893dd0484c 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -1,6 +1,7 @@
 //! `TypeFoldable` implementations for MIR types
 
 use rustc_ast::InlineAsmTemplatePiece;
+use rustc_hir::UnsafeBinderCastKind;
 use rustc_hir::def_id::LocalDefId;
 
 use super::*;
@@ -21,6 +22,7 @@ TrivialTypeTraversalImpls! {
     SwitchTargets,
     CoroutineKind,
     CoroutineSavedLocal,
+    UnsafeBinderCastKind,
 }
 
 TrivialTypeTraversalImpls! {
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 95de08ce9c8..8d04bbb95bd 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -636,7 +636,7 @@ macro_rules! make_mir_visitor {
                     OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
                         self.visit_operand(op, location);
                     }
-                    ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
+                    ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => {
                         // Nothing to visit
                     }
                     MisalignedPointerDereference { required, found } => {
@@ -781,6 +781,11 @@ macro_rules! make_mir_visitor {
                         self.visit_operand(operand, location);
                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
                     }
+
+                    Rvalue::WrapUnsafeBinder(op, ty) => {
+                        self.visit_operand(op, location);
+                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
+                    }
                 }
             }
 
@@ -1151,6 +1156,11 @@ macro_rules! visit_place_fns {
                     self.visit_ty(&mut new_ty, TyContext::Location(location));
                     if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
                 }
+                PlaceElem::UnwrapUnsafeBinder(ty) => {
+                    let mut new_ty = ty;
+                    self.visit_ty(&mut new_ty, TyContext::Location(location));
+                    if ty != new_ty { Some(PlaceElem::UnwrapUnsafeBinder(new_ty)) } else { None }
+                }
                 PlaceElem::Deref
                 | PlaceElem::ConstantIndex { .. }
                 | PlaceElem::Subslice { .. }
@@ -1219,7 +1229,8 @@ macro_rules! visit_place_fns {
             match elem {
                 ProjectionElem::OpaqueCast(ty)
                 | ProjectionElem::Subtype(ty)
-                | ProjectionElem::Field(_, ty) => {
+                | ProjectionElem::Field(_, ty)
+                | ProjectionElem::UnwrapUnsafeBinder(ty) => {
                     self.visit_ty(ty, TyContext::Location(location));
                 }
                 ProjectionElem::Index(local) => {
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index e243425c0b7..949d8303385 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -95,7 +95,7 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
     }
 }
 
-impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
+impl<'tcx> Key for (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>) {
     type Cache<V> = DefaultCache<Self, V>;
 
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
@@ -550,7 +550,7 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
     }
 }
 
-impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
+impl<'tcx> Key for ty::Value<'tcx> {
     type Cache<V> = DefaultCache<Self, V>;
 
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d83bc19a6a2..6c442fc1047 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -91,7 +91,7 @@ pub use keys::{AsLocalKey, Key, LocalCrate};
 pub mod on_disk_cache;
 #[macro_use]
 pub mod plumbing;
-pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue};
+pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk};
 
 // Each of these queries corresponds to a function pointer field in the
 // `Providers` struct for requesting a value of that type, and a method
@@ -1087,7 +1087,7 @@ rustc_queries! {
 
     query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) }
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
 
     /// Caches `CoerceUnsized` kinds for impls on custom types.
@@ -1095,7 +1095,7 @@ rustc_queries! {
         desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
 
     query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
@@ -1110,7 +1110,7 @@ rustc_queries! {
 
     query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
 
     /// Borrow-checks the function body. If this is a closure, returns
@@ -1140,7 +1140,7 @@ rustc_queries! {
     /// </div>
     query crate_inherent_impls_validity_check(_: ()) -> Result<(), ErrorGuaranteed> {
         desc { "check for inherent impls that should not be defined in crate" }
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
 
     /// Checks all types in the crate for overlap in their inherent impls. Reports errors.
@@ -1152,7 +1152,7 @@ rustc_queries! {
     /// </div>
     query crate_inherent_impls_overlap_check(_: ()) -> Result<(), ErrorGuaranteed> {
         desc { "check for overlap between inherent impls defined in this crate" }
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
 
     /// Checks whether all impls in the crate pass the overlap check, returning
@@ -1162,7 +1162,7 @@ rustc_queries! {
             "checking whether impl `{}` follows the orphan rules",
             tcx.def_path_str(key),
         }
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
 
     /// Check whether the function has any recursion that could cause the inliner to trigger
@@ -1256,9 +1256,9 @@ rustc_queries! {
         desc { "evaluating type-level constant" }
     }
 
-    /// Converts a type level constant value into `ConstValue`
-    query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> mir::ConstValue<'tcx> {
-        desc { "converting type-level constant value to mir constant value"}
+    /// Converts a type-level constant value into a MIR constant value.
+    query valtree_to_const_val(key: ty::Value<'tcx>) -> mir::ConstValue<'tcx> {
+        desc { "converting type-level constant value to MIR constant value"}
     }
 
     /// Destructures array, ADT or tuple constants into the constants
@@ -1437,9 +1437,9 @@ rustc_queries! {
         desc { |tcx| "finding all existential vtable entries for trait `{}`", tcx.def_path_str(key) }
     }
 
-    query vtable_entries(key: ty::PolyTraitRef<'tcx>)
+    query vtable_entries(key: ty::TraitRef<'tcx>)
                         -> &'tcx [ty::VtblEntry<'tcx>] {
-        desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) }
+        desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id) }
     }
 
     query first_method_vtable_slot(key: ty::TraitRef<'tcx>) -> usize {
@@ -1451,7 +1451,7 @@ rustc_queries! {
             key.1, key.0 }
     }
 
-    query vtable_allocation(key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId {
+    query vtable_allocation(key: (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId {
         desc { |tcx| "vtable const allocation for <{} as {}>",
             key.0,
             key.1.map(|trait_ref| format!("{trait_ref}")).unwrap_or("_".to_owned())
@@ -1479,7 +1479,7 @@ rustc_queries! {
     query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> {
         desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
         cache_on_disk_if { true }
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
     query dyn_compatibility_violations(trait_id: DefId) -> &'tcx [DynCompatibilityViolation] {
         desc { |tcx| "determining dyn-compatibility of trait `{}`", tcx.def_path_str(trait_id) }
@@ -1715,12 +1715,12 @@ rustc_queries! {
 
     query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) }
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
 
     query enforce_impl_non_lifetime_params_are_constrained(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking that `{}`'s generics are constrained by the impl header", tcx.def_path_str(key) }
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
 
     // The `DefId`s of all non-generic functions and statics in the given crate
@@ -2442,7 +2442,7 @@ rustc_queries! {
     /// Any other def id will ICE.
     query compare_impl_item(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking assoc item `{}` is compatible with trait definition", tcx.def_path_str(key) }
-        ensure_forwards_result_if_red
+        return_result_from_ensure_ok
     }
 
     query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 1c157f33a81..6c019b427db 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -88,30 +88,68 @@ impl<'tcx> Deref for TyCtxtAt<'tcx> {
 }
 
 #[derive(Copy, Clone)]
-pub struct TyCtxtEnsure<'tcx> {
+#[must_use]
+pub struct TyCtxtEnsureOk<'tcx> {
     pub tcx: TyCtxt<'tcx>,
 }
 
 #[derive(Copy, Clone)]
-pub struct TyCtxtEnsureWithValue<'tcx> {
+#[must_use]
+pub struct TyCtxtEnsureDone<'tcx> {
     pub tcx: TyCtxt<'tcx>,
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
-    /// are executed instead of just returning their results.
+    /// Wrapper that calls queries in a special "ensure OK" mode, for callers
+    /// that don't need the return value and just want to invoke a query for
+    /// its potential side-effect of emitting fatal errors.
+    ///
+    /// This can be more efficient than a normal query call, because if the
+    /// query's inputs are all green, the call can return immediately without
+    /// needing to obtain a value (by decoding one from disk or by executing
+    /// the query).
+    ///
+    /// (As with all query calls, execution is also skipped if the query result
+    /// is already cached in memory.)
+    ///
+    /// ## WARNING
+    /// A subsequent normal call to the same query might still cause it to be
+    /// executed! This can occur when the inputs are all green, but the query's
+    /// result is not cached on disk, so the query must be executed to obtain a
+    /// return value.
+    ///
+    /// Therefore, this call mode is not appropriate for callers that want to
+    /// ensure that the query is _never_ executed in the future.
+    ///
+    /// ## `return_result_from_ensure_ok`
+    /// If a query has the `return_result_from_ensure_ok` modifier, calls via
+    /// `ensure_ok` will instead return `Result<(), ErrorGuaranteed>`. If the
+    /// query needs to be executed, and execution returns an error, that error
+    /// is returned to the caller.
     #[inline(always)]
-    pub fn ensure(self) -> TyCtxtEnsure<'tcx> {
-        TyCtxtEnsure { tcx: self }
+    pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> {
+        TyCtxtEnsureOk { tcx: self }
     }
 
-    /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
-    /// are executed instead of just returning their results.
+    /// Wrapper that calls queries in a special "ensure done" mode, for callers
+    /// that don't need the return value and just want to guarantee that the
+    /// query won't be executed in the future, by executing it now if necessary.
     ///
-    /// This version verifies that the computed result exists in the cache before returning.
+    /// This is useful for queries that read from a [`Steal`] value, to ensure
+    /// that they are executed before the query that will steal the value.
+    ///
+    /// Unlike [`Self::ensure_ok`], a query with all-green inputs will only be
+    /// skipped if its return value is stored in the disk-cache. This is still
+    /// more efficient than a regular query, because in that situation the
+    /// return value doesn't necessarily need to be decoded.
+    ///
+    /// (As with all query calls, execution is also skipped if the query result
+    /// is already cached in memory.)
+    ///
+    /// [`Steal`]: rustc_data_structures::steal::Steal
     #[inline(always)]
-    pub fn ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx> {
-        TyCtxtEnsureWithValue { tcx: self }
+    pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> {
+        TyCtxtEnsureDone { tcx: self }
     }
 
     /// Returns a transparent wrapper for `TyCtxt` which uses
@@ -193,7 +231,7 @@ macro_rules! query_ensure {
     ([]$($args:tt)*) => {
         query_ensure($($args)*)
     };
-    ([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => {
+    ([(return_result_from_ensure_ok) $($rest:tt)*]$($args:tt)*) => {
         query_ensure_error_guaranteed($($args)*).map(|_| ())
     };
     ([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
@@ -248,15 +286,15 @@ macro_rules! separate_provide_extern_decl {
     };
 }
 
-macro_rules! ensure_result {
-    ([][$ty:ty]) => {
+macro_rules! ensure_ok_result {
+    ( [] ) => {
         ()
     };
-    ([(ensure_forwards_result_if_red) $($rest:tt)*][$ty:ty]) => {
+    ( [(return_result_from_ensure_ok) $($rest:tt)*] ) => {
         Result<(), ErrorGuaranteed>
     };
-    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
-        ensure_result!([$($modifiers)*][$($args)*])
+    ( [$other:tt $($modifiers:tt)*] ) => {
+        ensure_ok_result!( [$($modifiers)*] )
     };
 }
 
@@ -383,10 +421,13 @@ macro_rules! define_callbacks {
             $($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)*
         }
 
-        impl<'tcx> TyCtxtEnsure<'tcx> {
+        impl<'tcx> TyCtxtEnsureOk<'tcx> {
             $($(#[$attr])*
             #[inline(always)]
-            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> ensure_result!([$($modifiers)*][$V]) {
+            pub fn $name(
+                self,
+                key: query_helper_param_ty!($($K)*),
+            ) -> ensure_ok_result!([$($modifiers)*]) {
                 query_ensure!(
                     [$($modifiers)*]
                     self.tcx,
@@ -398,7 +439,7 @@ macro_rules! define_callbacks {
             })*
         }
 
-        impl<'tcx> TyCtxtEnsureWithValue<'tcx> {
+        impl<'tcx> TyCtxtEnsureDone<'tcx> {
             $($(#[$attr])*
             #[inline(always)]
             pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 86014c34b45..5490f1f53ea 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -18,7 +18,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd};
 use rustc_index::{IndexVec, newtype_index};
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable};
+use rustc_macros::{HashStable, TypeVisitable};
 use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp};
@@ -53,7 +53,7 @@ macro_rules! thir_with_elements {
         /// A container for a THIR body.
         ///
         /// This can be indexed directly by any THIR index (e.g. [`ExprId`]).
-        #[derive(Debug, HashStable, Clone)]
+        #[derive(Debug, HashStable)]
         pub struct Thir<'tcx> {
             $(
                 pub $field_name: $field_ty,
@@ -98,14 +98,14 @@ thir_with_elements! {
     params: ParamId => Param<'tcx> => "p{}",
 }
 
-#[derive(Debug, HashStable, Clone)]
+#[derive(Debug, HashStable)]
 pub enum BodyTy<'tcx> {
     Const(Ty<'tcx>),
     Fn(FnSig<'tcx>),
 }
 
 /// Description of a type-checked function parameter.
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct Param<'tcx> {
     /// The pattern that appears in the parameter list, or None for implicit parameters.
     pub pat: Option<Box<Pat<'tcx>>>,
@@ -125,7 +125,7 @@ pub enum LintLevel {
     Explicit(HirId),
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct Block {
     /// Whether the block itself has a label. Used by `label: {}`
     /// and `try` blocks.
@@ -145,7 +145,7 @@ pub struct Block {
 
 type UserTy<'tcx> = Option<Box<CanonicalUserType<'tcx>>>;
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct AdtExpr<'tcx> {
     /// The ADT we're constructing.
     pub adt_def: AdtDef<'tcx>,
@@ -162,7 +162,7 @@ pub struct AdtExpr<'tcx> {
     pub base: AdtExprBase<'tcx>,
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub enum AdtExprBase<'tcx> {
     /// A struct expression where all the fields are explicitly enumerated: `Foo { a, b }`.
     None,
@@ -175,7 +175,7 @@ pub enum AdtExprBase<'tcx> {
     DefaultFields(Box<[Ty<'tcx>]>),
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct ClosureExpr<'tcx> {
     pub closure_id: LocalDefId,
     pub args: UpvarArgs<'tcx>,
@@ -184,7 +184,7 @@ pub struct ClosureExpr<'tcx> {
     pub fake_reads: Vec<(ExprId, FakeReadCause, HirId)>,
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct InlineAsmExpr<'tcx> {
     pub asm_macro: AsmMacro,
     pub template: &'tcx [InlineAsmTemplatePiece],
@@ -202,12 +202,12 @@ pub enum BlockSafety {
     ExplicitUnsafe(HirId),
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct Stmt<'tcx> {
     pub kind: StmtKind<'tcx>,
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub enum StmtKind<'tcx> {
     /// An expression with a trailing semicolon.
     Expr {
@@ -247,11 +247,11 @@ pub enum StmtKind<'tcx> {
     },
 }
 
-#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, HashStable)]
 pub struct LocalVarId(pub HirId);
 
 /// A THIR expression.
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct Expr<'tcx> {
     /// kind of expression
     pub kind: ExprKind<'tcx>,
@@ -278,7 +278,7 @@ pub struct TempLifetime {
     pub backwards_incompatible: Option<region::Scope>,
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub enum ExprKind<'tcx> {
     /// `Scope`s are used to explicitly mark destruction scopes,
     /// and to track the `HirId` of the expressions within the scope.
@@ -489,6 +489,19 @@ pub enum ExprKind<'tcx> {
         user_ty: UserTy<'tcx>,
         user_ty_span: Span,
     },
+    /// An unsafe binder cast on a place, e.g. `unwrap_binder!(*ptr)`.
+    PlaceUnwrapUnsafeBinder {
+        source: ExprId,
+    },
+    /// An unsafe binder cast on a value, e.g. `unwrap_binder!(rvalue())`,
+    /// which makes a temporary.
+    ValueUnwrapUnsafeBinder {
+        source: ExprId,
+    },
+    /// Construct an unsafe binder, e.g. `wrap_binder(&ref)`.
+    WrapUnsafeBinder {
+        source: ExprId,
+    },
     /// A closure definition.
     Closure(Box<ClosureExpr<'tcx>>),
     /// A literal.
@@ -543,20 +556,20 @@ pub enum ExprKind<'tcx> {
 /// Represents the association of a field identifier and an expression.
 ///
 /// This is used in struct constructors.
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct FieldExpr {
     pub name: FieldIdx,
     pub expr: ExprId,
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct FruInfo<'tcx> {
     pub base: ExprId,
     pub field_types: Box<[Ty<'tcx>]>,
 }
 
 /// A `match` arm.
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub struct Arm<'tcx> {
     pub pattern: Box<Pat<'tcx>>,
     pub guard: Option<ExprId>,
@@ -574,7 +587,7 @@ pub enum LogicalOp {
     Or,
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Debug, HashStable)]
 pub enum InlineAsmOperand<'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
@@ -612,13 +625,13 @@ pub enum InlineAsmOperand<'tcx> {
     },
 }
 
-#[derive(Clone, Debug, HashStable, TypeVisitable)]
+#[derive(Debug, HashStable, TypeVisitable)]
 pub struct FieldPat<'tcx> {
     pub field: FieldIdx,
     pub pattern: Box<Pat<'tcx>>,
 }
 
-#[derive(Clone, Debug, HashStable, TypeVisitable)]
+#[derive(Debug, HashStable, TypeVisitable)]
 pub struct Pat<'tcx> {
     pub ty: Ty<'tcx>,
     pub span: Span,
@@ -726,7 +739,7 @@ impl<'tcx> Pat<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, HashStable, TypeVisitable)]
+#[derive(Debug, HashStable, TypeVisitable)]
 pub struct Ascription<'tcx> {
     pub annotation: CanonicalUserTypeAnnotation<'tcx>,
     /// Variance to use when relating the `user_ty` to the **type of the value being
@@ -750,7 +763,7 @@ pub struct Ascription<'tcx> {
     pub variance: ty::Variance,
 }
 
-#[derive(Clone, Debug, HashStable, TypeVisitable)]
+#[derive(Debug, HashStable, TypeVisitable)]
 pub enum PatKind<'tcx> {
     /// A wildcard pattern: `_`.
     Wild,
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 64bac12b266..2aeb13942a3 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -136,6 +136,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
         | ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
             visitor.visit_expr(&visitor.thir()[source])
         }
+        PlaceUnwrapUnsafeBinder { source }
+        | ValueUnwrapUnsafeBinder { source }
+        | WrapUnsafeBinder { source } => visitor.visit_expr(&visitor.thir()[source]),
         Closure(box ClosureExpr {
             closure_id: _,
             args: _,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 55d78e083e0..28a6eba75aa 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -194,6 +194,9 @@ pub enum ObligationCauseCode<'tcx> {
     /// A slice or array is WF only if `T: Sized`.
     SliceOrArrayElem,
 
+    /// An array `[T; N]` can only be indexed (and is only well-formed if) `N` has type usize.
+    ArrayLen(Ty<'tcx>),
+
     /// A tuple is WF only if its middle elements are `Sized`.
     TupleElem,
 
@@ -425,7 +428,7 @@ pub enum IsConstable {
     Ctor,
 }
 
-crate::TrivialTypeTraversalAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     IsConstable,
 }
 
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 31055276422..d77fb1cc91e 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -5,7 +5,6 @@ use rustc_error_messages::MultiSpan;
 use rustc_macros::HashStable;
 use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
 
-use crate::mir::interpret::Scalar;
 use crate::ty::{self, Ty, TyCtxt};
 
 mod int;
@@ -110,8 +109,8 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
-        Const::new(tcx, ty::ConstKind::Value(ty, val))
+    pub fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
+        Const::new(tcx, ty::ConstKind::Value(ty::Value { ty, valtree }))
     }
 
     #[inline]
@@ -214,47 +213,31 @@ impl<'tcx> Const<'tcx> {
         Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize)
     }
 
-    /// Panics if self.kind != ty::ConstKind::Value
-    pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
+    /// Panics if `self.kind != ty::ConstKind::Value`.
+    pub fn to_value(self) -> ty::Value<'tcx> {
         match self.kind() {
-            ty::ConstKind::Value(ty, valtree) => (valtree, ty),
+            ty::ConstKind::Value(cv) => cv,
             _ => bug!("expected ConstKind::Value, got {:?}", self.kind()),
         }
     }
 
-    /// Attempts to convert to a `ValTree`
-    pub fn try_to_valtree(self) -> Option<(ty::ValTree<'tcx>, Ty<'tcx>)> {
+    /// Attempts to convert to a value.
+    ///
+    /// Note that this does not evaluate the constant.
+    pub fn try_to_value(self) -> Option<ty::Value<'tcx>> {
         match self.kind() {
-            ty::ConstKind::Value(ty, valtree) => Some((valtree, ty)),
+            ty::ConstKind::Value(cv) => Some(cv),
             _ => None,
         }
     }
 
-    #[inline]
-    pub fn try_to_scalar(self) -> Option<(Scalar, Ty<'tcx>)> {
-        let (valtree, ty) = self.try_to_valtree()?;
-        Some((valtree.try_to_scalar()?, ty))
-    }
-
-    pub fn try_to_bool(self) -> Option<bool> {
-        self.try_to_valtree()?.0.try_to_scalar_int()?.try_to_bool().ok()
-    }
-
+    /// Convenience method to extract the value of a usize constant,
+    /// useful to get the length of an array type.
+    ///
+    /// Note that this does not evaluate the constant.
     #[inline]
     pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
-        self.try_to_valtree()?.0.try_to_target_usize(tcx)
-    }
-
-    /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
-    /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
-    /// contains const generic parameters or pointers).
-    #[inline]
-    pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
-        let (scalar, ty) = self.try_to_scalar()?;
-        let scalar = scalar.try_to_scalar_int().ok()?;
-        let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(ty);
-        let size = tcx.layout_of(input).ok()?.size;
-        Some(scalar.to_bits(size))
+        self.try_to_value()?.try_to_target_usize(tcx)
     }
 
     pub fn is_ct_infer(self) -> bool {
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index 9f9bf41c335..d914b7576dc 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -1,11 +1,9 @@
-use rustc_macros::{HashStable, TyDecodable, TyEncodable};
+use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 
 use super::ScalarInt;
 use crate::mir::interpret::Scalar;
 use crate::ty::{self, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq)]
-#[derive(HashStable)]
 /// This datastructure is used to represent the value of constants used in the type system.
 ///
 /// We explicitly choose a different datastructure from the way values are processed within
@@ -18,6 +16,8 @@ use crate::ty::{self, Ty, TyCtxt};
 ///
 /// `ValTree` does not have this problem with representation, as it only contains integers or
 /// lists of (nested) `ValTree`.
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(HashStable, TyEncodable, TyDecodable)]
 pub enum ValTree<'tcx> {
     /// integers, `bool`, `char` are represented as scalars.
     /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
@@ -79,10 +79,6 @@ impl<'tcx> ValTree<'tcx> {
         }
     }
 
-    pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
-        self.try_to_scalar_int().map(|s| s.to_target_usize(tcx))
-    }
-
     /// Get the values inside the ValTree as a slice of bytes. This only works for
     /// constants with types &str, &[u8], or [u8; _].
     pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> {
@@ -107,3 +103,54 @@ impl<'tcx> ValTree<'tcx> {
         )
     }
 }
+
+/// A type-level constant value.
+///
+/// Represents a typed, fully evaluated constant.
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
+pub struct Value<'tcx> {
+    pub ty: Ty<'tcx>,
+    pub valtree: ValTree<'tcx>,
+}
+
+impl<'tcx> Value<'tcx> {
+    /// Attempts to extract the raw bits from the constant.
+    ///
+    /// Fails if the value can't be represented as bits (e.g. because it is a reference
+    /// or an aggregate).
+    #[inline]
+    pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
+        let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else {
+            return None;
+        };
+        let scalar = self.valtree.try_to_scalar_int()?;
+        let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty);
+        let size = tcx.layout_of(input).ok()?.size;
+        Some(scalar.to_bits(size))
+    }
+
+    pub fn try_to_bool(self) -> Option<bool> {
+        if !self.ty.is_bool() {
+            return None;
+        }
+        self.valtree.try_to_scalar_int()?.try_to_bool().ok()
+    }
+
+    pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
+        if !self.ty.is_usize() {
+            return None;
+        }
+        self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx))
+    }
+}
+
+impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
+    fn ty(self) -> Ty<'tcx> {
+        self.ty
+    }
+
+    fn valtree(self) -> ValTree<'tcx> {
+        self.valtree
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 0c22c056dab..522a553d243 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -142,10 +142,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
 
     type ParamConst = ty::ParamConst;
     type BoundConst = ty::BoundVar;
-    type ValueConst = ty::ValTree<'tcx>;
+    type ValueConst = ty::Value<'tcx>;
     type ExprConst = ty::Expr<'tcx>;
-    type Region = Region<'tcx>;
+    type ValTree = ty::ValTree<'tcx>;
 
+    type Region = Region<'tcx>;
     type EarlyParamRegion = ty::EarlyParamRegion;
     type LateParamRegion = ty::LateParamRegion;
     type BoundRegion = ty::BoundRegion;
@@ -1118,15 +1119,18 @@ impl<'tcx> CommonConsts<'tcx> {
         };
 
         CommonConsts {
-            unit: mk_const(ty::ConstKind::Value(types.unit, ty::ValTree::zst())),
-            true_: mk_const(ty::ConstKind::Value(
-                types.bool,
-                ty::ValTree::Leaf(ty::ScalarInt::TRUE),
-            )),
-            false_: mk_const(ty::ConstKind::Value(
-                types.bool,
-                ty::ValTree::Leaf(ty::ScalarInt::FALSE),
-            )),
+            unit: mk_const(ty::ConstKind::Value(ty::Value {
+                ty: types.unit,
+                valtree: ty::ValTree::zst(),
+            })),
+            true_: mk_const(ty::ConstKind::Value(ty::Value {
+                ty: types.bool,
+                valtree: ty::ValTree::Leaf(ty::ScalarInt::TRUE),
+            })),
+            false_: mk_const(ty::ConstKind::Value(ty::Value {
+                ty: types.bool,
+                valtree: ty::ValTree::Leaf(ty::ScalarInt::FALSE),
+            })),
         }
     }
 }
@@ -1953,7 +1957,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap {
         // Create a dependency to the crate to be sure we re-execute this when the amount of
         // definitions change.
-        self.ensure().hir_crate(());
+        self.ensure_ok().hir_crate(());
         // Freeze definitions once we start iterating on them, to prevent adding new ones
         // while iterating. If some query needs to add definitions, it should be `ensure`d above.
         self.untracked.definitions.freeze().def_path_hash_to_def_index_map()
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index b4b66a8133a..cb218a27e62 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -5,7 +5,7 @@ use std::ops::ControlFlow;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{
-    Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, pluralize,
+    Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, listify, pluralize,
 };
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -362,11 +362,8 @@ pub fn suggest_constraining_type_params<'a>(
             let n = trait_names.len();
             let stable = if all_stable { "" } else { "unstable " };
             let trait_ = if all_known { format!("trait{}", pluralize!(n)) } else { String::new() };
-            format!("{stable}{trait_}{}", match &trait_names[..] {
-                [t] => format!(" {t}"),
-                [ts @ .., last] => format!(" {} and {last}", ts.join(", ")),
-                [] => return false,
-            },)
+            let Some(trait_names) = listify(&trait_names, |n| n.to_string()) else { return false };
+            format!("{stable}{trait_} {trait_names}")
         } else {
             // We're more explicit when there's a mix of stable and unstable traits.
             let mut trait_names = constraints
@@ -378,10 +375,9 @@ pub fn suggest_constraining_type_params<'a>(
                 .collect::<Vec<_>>();
             trait_names.sort();
             trait_names.dedup();
-            match &trait_names[..] {
-                [t] => t.to_string(),
-                [ts @ .., last] => format!("{} and {last}", ts.join(", ")),
-                [] => return false,
+            match listify(&trait_names, |t| t.to_string()) {
+                Some(names) => names,
+                None => return false,
             }
         };
         let constraint = constraint.join(" + ");
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 35fbaa99569..8c1991ddb36 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -10,8 +10,8 @@ use rustc_hir::def::{CtorOf, DefKind};
 use rustc_macros::extension;
 pub use rustc_type_ir::error::ExpectedFound;
 
-use crate::ty::print::{FmtPrinter, PrettyPrinter, with_forced_trimmed_paths};
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::print::{FmtPrinter, Print, with_forced_trimmed_paths};
+use crate::ty::{self, Lift, Ty, TyCtxt};
 
 pub type TypeError<'tcx> = rustc_type_ir::error::TypeError<TyCtxt<'tcx>>;
 
@@ -159,8 +159,8 @@ impl<'tcx> Ty<'tcx> {
             ty::Error(_) => "type error".into(),
             _ => {
                 let width = tcx.sess.diagnostic_width();
-                let length_limit = std::cmp::max(width / 4, 15);
-                format!("`{}`", tcx.ty_string_with_limit(self, length_limit)).into()
+                let length_limit = std::cmp::max(width / 4, 40);
+                format!("`{}`", tcx.string_with_limit(self, length_limit)).into()
             }
         }
     }
@@ -213,10 +213,14 @@ impl<'tcx> Ty<'tcx> {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String {
+    pub fn string_with_limit<'a, T>(self, p: T, length_limit: usize) -> String
+    where
+        T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy,
+        <T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
+    {
         let mut type_limit = 50;
         let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
-            cx.pretty_print_type(ty)
+            self.lift(p).expect("could not lift for printing").print(cx)
         })
         .expect("could not write to `String`");
         if regular.len() <= length_limit {
@@ -231,7 +235,10 @@ impl<'tcx> TyCtxt<'tcx> {
                     hir::def::Namespace::TypeNS,
                     rustc_session::Limit(type_limit),
                 );
-                cx.pretty_print_type(ty).expect("could not write to `String`");
+                self.lift(p)
+                    .expect("could not lift for printing")
+                    .print(&mut cx)
+                    .expect("could not print type");
                 cx.into_buffer()
             });
             if short.len() <= length_limit || type_limit == 0 {
@@ -242,9 +249,17 @@ impl<'tcx> TyCtxt<'tcx> {
         short
     }
 
-    pub fn short_ty_string(self, ty: Ty<'tcx>, path: &mut Option<PathBuf>) -> String {
+    /// When calling this after a `Diag` is constructed, the preferred way of doing so is
+    /// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps
+    /// the existence of a "long type" anywhere in the diagnostic, so the note telling the user
+    /// where we wrote the file to is only printed once.
+    pub fn short_string<'a, T>(self, p: T, path: &mut Option<PathBuf>) -> String
+    where
+        T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy + Hash,
+        <T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>,
+    {
         let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
-            cx.pretty_print_type(ty)
+            self.lift(p).expect("could not lift for printing").print(cx)
         })
         .expect("could not write to `String`");
 
@@ -257,13 +272,13 @@ impl<'tcx> TyCtxt<'tcx> {
         if regular.len() <= width * 2 / 3 {
             return regular;
         }
-        let short = self.ty_string_with_limit(ty, length_limit);
+        let short = self.string_with_limit(p, length_limit);
         if regular == short {
             return regular;
         }
         // Ensure we create an unique file for the type passed in when we create a file.
         let mut s = DefaultHasher::new();
-        ty.hash(&mut s);
+        p.hash(&mut s);
         let hash = s.finish();
         *path = Some(path.take().unwrap_or_else(|| {
             self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None)
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 0af57f636aa..ec0498b168c 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -381,7 +381,7 @@ impl FlagComputation {
                 self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
             }
-            ty::ConstKind::Value(ty, _) => self.add_ty(ty),
+            ty::ConstKind::Value(cv) => self.add_ty(cv.ty),
             ty::ConstKind::Expr(e) => self.add_args(e.args()),
             ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
         }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 0d41a1d7dbf..3ced64b5b80 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -504,6 +504,9 @@ impl<'tcx> SizeSkeleton<'tcx> {
                 }
             }
 
+            // Pattern types are always the same size as their base.
+            ty::Pat(base, _) => SizeSkeleton::compute(base, tcx, typing_env),
+
             _ => Err(err),
         }
     }
@@ -855,7 +858,12 @@ where
                     }
 
                     let mk_dyn_vtable = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
-                        let min_count = ty::vtable_min_entries(tcx, principal);
+                        let min_count = ty::vtable_min_entries(
+                            tcx,
+                            principal.map(|principal| {
+                                tcx.instantiate_bound_regions_with_erased(principal)
+                            }),
+                        );
                         Ty::new_imm_ref(
                             tcx,
                             tcx.lifetimes.re_static,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8cd632790a8..88eea6101b5 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -60,7 +60,7 @@ pub use self::closure::{
     place_to_string_for_capture,
 };
 pub use self::consts::{
-    Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree,
+    Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, Value,
 };
 pub use self::context::{
     CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 6b6c6f3c72f..8eaf0a58f70 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -101,6 +101,7 @@ trivially_parameterized_over_tcx! {
     rustc_session::cstore::ForeignModule,
     rustc_session::cstore::LinkagePreference,
     rustc_session::cstore::NativeLib,
+    rustc_session::config::TargetModifier,
     rustc_span::ExpnData,
     rustc_span::ExpnHash,
     rustc_span::ExpnId,
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 72f353f06ff..dc2040aa5cf 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -105,6 +105,10 @@ pub trait Printer<'tcx>: Sized {
         args: &[GenericArg<'tcx>],
     ) -> Result<(), PrintError>;
 
+    fn should_truncate(&mut self) -> bool {
+        false
+    }
+
     // Defaults (should not be overridden):
 
     #[instrument(skip(self), level = "debug")]
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index ac900edefe1..6c8591dae89 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -865,7 +865,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 p!(write("{{"));
                 if !self.tcx().sess.verbose_internals() {
                     p!("coroutine witness");
-                    // FIXME(eddyb) should use `def_span`.
                     if let Some(did) = did.as_local() {
                         let span = self.tcx().def_span(did);
                         p!(write(
@@ -887,26 +886,30 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 p!(write("{{"));
                 if !self.should_print_verbose() {
                     p!(write("closure"));
-                    // FIXME(eddyb) should use `def_span`.
-                    if let Some(did) = did.as_local() {
-                        if self.tcx().sess.opts.unstable_opts.span_free_formats {
-                            p!("@", print_def_path(did.to_def_id(), args));
-                        } else {
-                            let span = self.tcx().def_span(did);
-                            let preference = if with_forced_trimmed_paths() {
-                                FileNameDisplayPreference::Short
+                    if self.should_truncate() {
+                        write!(self, "@...}}")?;
+                        return Ok(());
+                    } else {
+                        if let Some(did) = did.as_local() {
+                            if self.tcx().sess.opts.unstable_opts.span_free_formats {
+                                p!("@", print_def_path(did.to_def_id(), args));
                             } else {
-                                FileNameDisplayPreference::Remapped
-                            };
-                            p!(write(
-                                "@{}",
-                                // This may end up in stderr diagnostics but it may also be emitted
-                                // into MIR. Hence we use the remapped path if available
-                                self.tcx().sess.source_map().span_to_string(span, preference)
-                            ));
+                                let span = self.tcx().def_span(did);
+                                let preference = if with_forced_trimmed_paths() {
+                                    FileNameDisplayPreference::Short
+                                } else {
+                                    FileNameDisplayPreference::Remapped
+                                };
+                                p!(write(
+                                    "@{}",
+                                    // This may end up in stderr diagnostics but it may also be emitted
+                                    // into MIR. Hence we use the remapped path if available
+                                    self.tcx().sess.source_map().span_to_string(span, preference)
+                                ));
+                            }
+                        } else {
+                            p!(write("@"), print_def_path(did, args));
                         }
-                    } else {
-                        p!(write("@"), print_def_path(did, args));
                     }
                 } else {
                     p!(print_def_path(did, args));
@@ -942,7 +945,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                             "coroutine from coroutine-closure should have CoroutineSource::Closure"
                         ),
                     }
-                    // FIXME(eddyb) should use `def_span`.
                     if let Some(did) = did.as_local() {
                         if self.tcx().sess.opts.unstable_opts.span_free_formats {
                             p!("@", print_def_path(did.to_def_id(), args));
@@ -1484,8 +1486,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 _ => write!(self, "_")?,
             },
             ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
-            ty::ConstKind::Value(ty, value) => {
-                return self.pretty_print_const_valtree(value, ty, print_ty);
+            ty::ConstKind::Value(cv) => {
+                return self.pretty_print_const_valtree(cv.valtree, cv.ty, print_ty);
             }
 
             ty::ConstKind::Bound(debruijn, bound_var) => {
@@ -1637,33 +1639,32 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         match ty.kind() {
             // Byte strings (&[u8; N])
             ty::Ref(_, inner, _) => {
-                if let ty::Array(elem, len) = inner.kind() {
-                    if let ty::Uint(ty::UintTy::U8) = elem.kind() {
-                        if let ty::ConstKind::Value(_, ty::ValTree::Leaf(int)) = len.kind() {
-                            match self.tcx().try_get_global_alloc(prov.alloc_id()) {
-                                Some(GlobalAlloc::Memory(alloc)) => {
-                                    let len = int.to_bits(self.tcx().data_layout.pointer_size);
-                                    let range =
-                                        AllocRange { start: offset, size: Size::from_bytes(len) };
-                                    if let Ok(byte_str) =
-                                        alloc.inner().get_bytes_strip_provenance(&self.tcx(), range)
-                                    {
-                                        p!(pretty_print_byte_str(byte_str))
-                                    } else {
-                                        p!("<too short allocation>")
-                                    }
-                                }
-                                // FIXME: for statics, vtables, and functions, we could in principle print more detail.
-                                Some(GlobalAlloc::Static(def_id)) => {
-                                    p!(write("<static({:?})>", def_id))
-                                }
-                                Some(GlobalAlloc::Function { .. }) => p!("<function>"),
-                                Some(GlobalAlloc::VTable(..)) => p!("<vtable>"),
-                                None => p!("<dangling pointer>"),
+                if let ty::Array(elem, len) = inner.kind()
+                    && let ty::Uint(ty::UintTy::U8) = elem.kind()
+                    && let ty::ConstKind::Value(cv) = len.kind()
+                    && let ty::ValTree::Leaf(int) = cv.valtree
+                {
+                    match self.tcx().try_get_global_alloc(prov.alloc_id()) {
+                        Some(GlobalAlloc::Memory(alloc)) => {
+                            let len = int.to_bits(self.tcx().data_layout.pointer_size);
+                            let range = AllocRange { start: offset, size: Size::from_bytes(len) };
+                            if let Ok(byte_str) =
+                                alloc.inner().get_bytes_strip_provenance(&self.tcx(), range)
+                            {
+                                p!(pretty_print_byte_str(byte_str))
+                            } else {
+                                p!("<too short allocation>")
                             }
-                            return Ok(());
                         }
+                        // FIXME: for statics, vtables, and functions, we could in principle print more detail.
+                        Some(GlobalAlloc::Static(def_id)) => {
+                            p!(write("<static({:?})>", def_id))
+                        }
+                        Some(GlobalAlloc::Function { .. }) => p!("<function>"),
+                        Some(GlobalAlloc::VTable(..)) => p!("<vtable>"),
+                        None => p!("<dangling pointer>"),
                     }
+                    return Ok(());
                 }
             }
             ty::FnPtr(..) => {
@@ -1740,6 +1741,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     " as ",
                 )?;
             }
+            ty::Pat(base_ty, pat) => {
+                self.pretty_print_const_scalar_int(int, *base_ty, print_ty)?;
+                p!(write(" is {pat:?}"));
+            }
             // Nontrivial types with scalar bit representation
             _ => {
                 let print = |this: &mut Self| {
@@ -1782,6 +1787,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         Ok(())
     }
 
+    // FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately.
     fn pretty_print_const_valtree(
         &mut self,
         valtree: ty::ValTree<'tcx>,
@@ -1990,7 +1996,6 @@ pub struct FmtPrinterData<'a, 'tcx> {
     binder_depth: usize,
     printed_type_count: usize,
     type_length_limit: Limit,
-    truncated: bool,
 
     pub region_highlight_mode: RegionHighlightMode<'tcx>,
 
@@ -2042,7 +2047,6 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
             binder_depth: 0,
             printed_type_count: 0,
             type_length_limit,
-            truncated: false,
             region_highlight_mode: RegionHighlightMode::default(),
             ty_infer_name_resolver: None,
             const_infer_name_resolver: None,
@@ -2179,16 +2183,49 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
     }
 
     fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
-        if self.type_length_limit.value_within_limit(self.printed_type_count) {
-            self.printed_type_count += 1;
-            self.pretty_print_type(ty)
-        } else {
-            self.truncated = true;
-            write!(self, "...")?;
-            Ok(())
+        match ty.kind() {
+            ty::Tuple(tys) if tys.len() == 0 && self.should_truncate() => {
+                // Don't truncate `()`.
+                self.printed_type_count += 1;
+                self.pretty_print_type(ty)
+            }
+            ty::Adt(..)
+            | ty::Foreign(_)
+            | ty::Pat(..)
+            | ty::RawPtr(..)
+            | ty::Ref(..)
+            | ty::FnDef(..)
+            | ty::FnPtr(..)
+            | ty::UnsafeBinder(..)
+            | ty::Dynamic(..)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
+            | ty::Coroutine(..)
+            | ty::CoroutineWitness(..)
+            | ty::Tuple(_)
+            | ty::Alias(..)
+            | ty::Param(_)
+            | ty::Bound(..)
+            | ty::Placeholder(_)
+            | ty::Error(_)
+                if self.should_truncate() =>
+            {
+                // We only truncate types that we know are likely to be much longer than 3 chars.
+                // There's no point in replacing `i32` or `!`.
+                write!(self, "...")?;
+                Ok(())
+            }
+            _ => {
+                self.printed_type_count += 1;
+                self.pretty_print_type(ty)
+            }
         }
     }
 
+    fn should_truncate(&mut self) -> bool {
+        !self.type_length_limit.value_within_limit(self.printed_type_count)
+    }
+
     fn print_dyn_existential(
         &mut self,
         predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@@ -2938,7 +2975,7 @@ impl<'tcx> ty::TraitPredicate<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)]
 pub struct TraitPredPrintWithBoundConstness<'tcx>(
     ty::TraitPredicate<'tcx>,
     Option<ty::BoundConstness>,
diff --git a/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs b/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs
index cbc02097d82..568e504b940 100644
--- a/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs
+++ b/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs
@@ -4,7 +4,7 @@ use crate::ty::{self, ExistentialPredicateStableCmpExt, TyCtxt};
 
 impl<'tcx> TyCtxt<'tcx> {
     /// Given a `def_id` of a trait or impl method, compute whether that method needs to
-    /// have an RPITIT shim applied to it for it to be object safe. If so, return the
+    /// have an RPITIT shim applied to it for it to be dyn compatible. If so, return the
     /// `def_id` of the RPITIT, and also the args of trait method that returns the RPITIT.
     ///
     /// NOTE that these args are not, in general, the same as than the RPITIT's args. They
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 68cb56f3583..9e9de4fb064 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -162,16 +162,15 @@ impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
 impl<'tcx> fmt::Debug for ty::Const<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // If this is a value, we spend some effort to make it look nice.
-        if let ConstKind::Value(_, _) = self.kind() {
+        if let ConstKind::Value(_) = self.kind() {
             return ty::tls::with(move |tcx| {
-                // Somehow trying to lift the valtree results in lifetime errors, so we lift the
-                // entire constant.
+                // ValTrees aren't interned, so we lift the entire constant.
                 let lifted = tcx.lift(*self).unwrap();
-                let ConstKind::Value(ty, valtree) = lifted.kind() else {
+                let ConstKind::Value(cv) = lifted.kind() else {
                     bug!("we checked that this is a valtree")
                 };
                 let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
-                cx.pretty_print_const_valtree(valtree, ty, /*print_ty*/ true)?;
+                cx.pretty_print_const_valtree(cv.valtree, cv.ty, /*print_ty*/ true)?;
                 f.write_str(&cx.into_buffer())
             });
         }
@@ -589,9 +588,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
             }
             ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?),
             ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?),
-            ConstKind::Value(t, v) => {
-                ConstKind::Value(t.try_fold_with(folder)?, v.try_fold_with(folder)?)
-            }
+            ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?),
             ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?),
             ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?),
         };
@@ -610,10 +607,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
             }
             ConstKind::Placeholder(p) => p.visit_with(visitor),
             ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
-            ConstKind::Value(t, v) => {
-                try_visit!(t.visit_with(visitor));
-                v.visit_with(visitor)
-            }
+            ConstKind::Value(v) => v.visit_with(visitor),
             ConstKind::Error(e) => e.visit_with(visitor),
             ConstKind::Expr(e) => e.visit_with(visitor),
         }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 7d5e5c2e823..318bd0c7ec0 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -367,7 +367,7 @@ impl<'tcx> TyCtxt<'tcx> {
         validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
     ) -> Option<ty::Destructor> {
         let drop_trait = self.lang_items().drop_trait()?;
-        self.ensure().coherent_trait(drop_trait).ok()?;
+        self.ensure_ok().coherent_trait(drop_trait).ok()?;
 
         let ty = self.type_of(adt_did).instantiate_identity();
         let mut dtor_candidate = None;
@@ -404,7 +404,7 @@ impl<'tcx> TyCtxt<'tcx> {
         validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
     ) -> Option<ty::AsyncDestructor> {
         let async_drop_trait = self.lang_items().async_drop_trait()?;
-        self.ensure().coherent_trait(async_drop_trait).ok()?;
+        self.ensure_ok().coherent_trait(async_drop_trait).ok()?;
 
         let ty = self.type_of(adt_did).instantiate_identity();
         let mut dtor_candidate = None;
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 23e2e8ad3d3..6c9e0e7c0eb 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -4,8 +4,10 @@ use rustc_ast::Mutability;
 use rustc_macros::HashStable;
 use rustc_type_ir::elaborate;
 
-use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range};
-use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
+use crate::mir::interpret::{
+    AllocId, AllocInit, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range,
+};
+use crate::ty::{self, Instance, TraitRef, Ty, TyCtxt};
 
 #[derive(Clone, Copy, PartialEq, HashStable)]
 pub enum VtblEntry<'tcx> {
@@ -20,7 +22,7 @@ pub enum VtblEntry<'tcx> {
     /// dispatchable associated function
     Method(Instance<'tcx>),
     /// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
-    TraitVPtr(PolyTraitRef<'tcx>),
+    TraitVPtr(TraitRef<'tcx>),
 }
 
 impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
@@ -57,7 +59,7 @@ pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
 // function is an accurate approximation. We verify this when actually computing the vtable below.
 pub(crate) fn vtable_min_entries<'tcx>(
     tcx: TyCtxt<'tcx>,
-    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
 ) -> usize {
     let mut count = TyCtxt::COMMON_VTABLE_ENTRIES.len();
     let Some(trait_ref) = trait_ref else {
@@ -65,7 +67,7 @@ pub(crate) fn vtable_min_entries<'tcx>(
     };
 
     // This includes self in supertraits.
-    for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id()) {
+    for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id) {
         count += tcx.own_existential_vtable_entries(def_id).len();
     }
 
@@ -81,7 +83,7 @@ pub(crate) fn vtable_min_entries<'tcx>(
 /// initial contents.)
 pub(super) fn vtable_allocation_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
-    key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
+    key: (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>),
 ) -> AllocId {
     let (ty, poly_trait_ref) = key;
 
@@ -108,7 +110,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
     let ptr_align = tcx.data_layout.pointer_align.abi;
 
     let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
-    let mut vtable = Allocation::uninit(vtable_size, ptr_align);
+    let mut vtable = Allocation::new(vtable_size, ptr_align, AllocInit::Uninit);
 
     // No need to do any alignment checks on the memory accesses below, because we know the
     // allocation is correctly aligned as we created it above. Also we're only offsetting by
@@ -116,7 +118,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
 
     for (idx, entry) in vtable_entries.iter().enumerate() {
         let idx: u64 = u64::try_from(idx).unwrap();
-        let scalar = match entry {
+        let scalar = match *entry {
             VtblEntry::MetadataDropInPlace => {
                 if ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) {
                     let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
@@ -132,13 +134,12 @@ pub(super) fn vtable_allocation_provider<'tcx>(
             VtblEntry::Vacant => continue,
             VtblEntry::Method(instance) => {
                 // Prepare the fn ptr we write into the vtable.
-                let fn_alloc_id = tcx.reserve_and_set_fn_alloc(*instance, CTFE_ALLOC_SALT);
+                let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT);
                 let fn_ptr = Pointer::from(fn_alloc_id);
                 Scalar::from_pointer(fn_ptr, &tcx)
             }
             VtblEntry::TraitVPtr(trait_ref) => {
-                let super_trait_ref = trait_ref
-                    .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+                let super_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref);
                 let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref)));
                 let vptr = Pointer::from(supertrait_alloc_id);
                 Scalar::from_pointer(vptr, &tcx)
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 2dcba8c2f82..3e8a3d1a289 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -206,7 +206,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
             | ty::ConstKind::Bound(..)
             | ty::ConstKind::Error(_) => {}
 
-            ty::ConstKind::Value(ty, _) => stack.push(ty.into()),
+            ty::ConstKind::Value(cv) => stack.push(cv.ty.into()),
 
             ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()),
             ty::ConstKind::Unevaluated(ct) => {
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index b99336c2c85..7dda68b8393 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -1,4 +1,4 @@
-// These functions are used by macro expansion for bug! and span_bug!
+// These functions are used by macro expansion for `bug!` and `span_bug!`.
 
 use std::fmt;
 use std::panic::{Location, panic_any};
@@ -8,15 +8,15 @@ use rustc_span::Span;
 
 use crate::ty::{TyCtxt, tls};
 
+// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly.
 #[cold]
 #[inline(never)]
 #[track_caller]
 pub fn bug_fmt(args: fmt::Arguments<'_>) -> ! {
-    // this wrapper mostly exists so I don't have to write a fully
-    // qualified path of None::<Span> inside the bug!() macro definition
     opt_span_bug_fmt(None::<Span>, args, Location::caller());
 }
 
+// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly.
 #[cold]
 #[inline(never)]
 #[track_caller]
diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs
deleted file mode 100644
index 223b2b3bfe4..00000000000
--- a/compiler/rustc_middle/src/util/common.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-#[cfg(test)]
-mod tests;
-
-pub fn to_readable_str(mut val: usize) -> String {
-    let mut groups = vec![];
-    loop {
-        let group = val % 1000;
-
-        val /= 1000;
-
-        if val == 0 {
-            groups.push(group.to_string());
-            break;
-        } else {
-            groups.push(format!("{group:03}"));
-        }
-    }
-
-    groups.reverse();
-
-    groups.join("_")
-}
diff --git a/compiler/rustc_middle/src/util/common/tests.rs b/compiler/rustc_middle/src/util/common/tests.rs
deleted file mode 100644
index 9a9fb203c62..00000000000
--- a/compiler/rustc_middle/src/util/common/tests.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use super::*;
-
-#[test]
-fn test_to_readable_str() {
-    assert_eq!("0", to_readable_str(0));
-    assert_eq!("1", to_readable_str(1));
-    assert_eq!("99", to_readable_str(99));
-    assert_eq!("999", to_readable_str(999));
-    assert_eq!("1_000", to_readable_str(1_000));
-    assert_eq!("1_001", to_readable_str(1_001));
-    assert_eq!("999_999", to_readable_str(999_999));
-    assert_eq!("1_000_000", to_readable_str(1_000_000));
-    assert_eq!("1_234_567", to_readable_str(1_234_567));
-}
diff --git a/compiler/rustc_middle/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs
deleted file mode 100644
index 0fdd3520738..00000000000
--- a/compiler/rustc_middle/src/util/find_self_call.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-use rustc_span::def_id::DefId;
-use rustc_span::source_map::Spanned;
-use tracing::debug;
-
-use crate::mir::*;
-use crate::ty::{self, GenericArgsRef, TyCtxt};
-
-/// Checks if the specified `local` is used as the `self` parameter of a method call
-/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
-/// returned.
-pub fn find_self_call<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    local: Local,
-    block: BasicBlock,
-) -> Option<(DefId, GenericArgsRef<'tcx>)> {
-    debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator);
-    if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
-        &body[block].terminator
-        && let Operand::Constant(box ConstOperand { const_, .. }) = func
-        && let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
-        && let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
-            tcx.opt_associated_item(def_id)
-        && let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
-            **args
-    {
-        if self_place.as_local() == Some(local) {
-            return Some((def_id, fn_args));
-        }
-
-        // Handle the case where `self_place` gets reborrowed.
-        // This happens when the receiver is `&T`.
-        for stmt in &body[block].statements {
-            if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
-                && let Some(reborrow_local) = place.as_local()
-                && self_place.as_local() == Some(reborrow_local)
-                && let Rvalue::Ref(_, _, deref_place) = rvalue
-                && let PlaceRef { local: deref_local, projection: [ProjectionElem::Deref] } =
-                    deref_place.as_ref()
-                && deref_local == local
-            {
-                return Some((def_id, fn_args));
-            }
-        }
-    }
-    None
-}
diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs
index 097a868191c..8c875007b7f 100644
--- a/compiler/rustc_middle/src/util/mod.rs
+++ b/compiler/rustc_middle/src/util/mod.rs
@@ -1,8 +1,4 @@
 pub mod bug;
-pub mod common;
-pub mod find_self_call;
-
-pub use find_self_call::find_self_call;
 
 #[derive(Default, Copy, Clone)]
 pub struct Providers {
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 053775b4937..3cf3c332893 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -25,8 +25,6 @@ mir_build_borrow_of_moved_value = borrow of moved value
     .occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait
     .value_borrowed_label = value borrowed here after move
     .suggestion = borrow this binding in the pattern to avoid moving the value
-    .full_type_name = the full type name has been written to '{$path}'
-    .consider_verbose = consider using `--verbose` to print the full type name to the console
 
 mir_build_call_to_deprecated_safe_fn_requires_unsafe =
     call to deprecated safe function `{$function}` is unsafe and requires unsafe block
@@ -361,6 +359,18 @@ mir_build_unreachable_pattern = unreachable pattern
     .unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings
     .suggestion = remove the match arm
 
+mir_build_unsafe_binder_cast_requires_unsafe =
+    unsafe binder cast is unsafe and requires unsafe block
+    .label = unsafe binder cast
+    .note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime
+        information that may be required to uphold safety guarantees of a type
+
+mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    unsafe binder cast is unsafe and requires unsafe block or unsafe fn
+    .label = unsafe binder cast
+    .note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime
+        information that may be required to uphold safety guarantees of a type
+
 mir_build_unsafe_field_requires_unsafe =
     use of unsafe field is unsafe and requires unsafe block
     .note = unsafe fields may carry library invariants
diff --git a/compiler/rustc_mir_build/src/builder/custom/mod.rs b/compiler/rustc_mir_build/src/builder/custom/mod.rs
index ca2e1dd7a1a..bfc16816e2e 100644
--- a/compiler/rustc_mir_build/src/builder/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/custom/mod.rs
@@ -6,7 +6,7 @@
 //! present, and if so we branch off into this module, which implements the attribute by
 //! implementing a custom lowering from THIR to MIR.
 //!
-//! The result of this lowering is returned "normally" from the `build_mir` hook, with the only
+//! The result of this lowering is returned "normally" from `build_mir`, with the only
 //! notable difference being that the `injected` field in the body is set. Various components of the
 //! MIR pipeline, like borrowck and the pass manager will then consult this field (via
 //! `body.should_skip()`) to skip the parts of the MIR pipeline that precede the MIR phase the user
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs
index 0086775e9f4..482f1e3840b 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs
@@ -105,7 +105,8 @@ fn convert_to_hir_projections_and_truncate_for_capture(
             ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
             ProjectionElem::Index(..)
             | ProjectionElem::ConstantIndex { .. }
-            | ProjectionElem::Subslice { .. } => {
+            | ProjectionElem::Subslice { .. }
+            | ProjectionElem::UnwrapUnsafeBinder(_) => {
                 // We don't capture array-access projections.
                 // We can stop here as arrays are captured completely.
                 break;
@@ -523,6 +524,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(PlaceBuilder::from(temp))
             }
 
+            ExprKind::PlaceUnwrapUnsafeBinder { source } => {
+                let place_builder = unpack!(
+                    block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
+                );
+                block.and(place_builder.project(PlaceElem::UnwrapUnsafeBinder(expr.ty)))
+            }
+            ExprKind::ValueUnwrapUnsafeBinder { source } => {
+                let source_expr = &this.thir[source];
+                let temp = unpack!(
+                    block = this.as_temp(block, source_expr.temp_lifetime, source, mutability)
+                );
+                block.and(PlaceBuilder::from(temp).project(PlaceElem::UnwrapUnsafeBinder(expr.ty)))
+            }
+
             ExprKind::Array { .. }
             | ExprKind::Tuple { .. }
             | ExprKind::Adt { .. }
@@ -560,7 +575,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::OffsetOf { .. }
             | ExprKind::Yield { .. }
             | ExprKind::ThreadLocalRef(_)
-            | ExprKind::Call { .. } => {
+            | ExprKind::Call { .. }
+            | ExprKind::WrapUnsafeBinder { .. } => {
                 // these are not places, so we need to make a temporary.
                 debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
                 let temp =
@@ -776,7 +792,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     | ProjectionElem::OpaqueCast(..)
                     | ProjectionElem::Subtype(..)
                     | ProjectionElem::ConstantIndex { .. }
-                    | ProjectionElem::Subslice { .. } => (),
+                    | ProjectionElem::Subslice { .. }
+                    | ProjectionElem::UnwrapUnsafeBinder(_) => (),
                 }
             }
         }
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
index 9961c2488ef..e7713f0a1d6 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
@@ -508,6 +508,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(Rvalue::Use(Operand::Constant(Box::new(constant))))
             }
 
+            ExprKind::WrapUnsafeBinder { source } => {
+                let source = unpack!(
+                    block = this.as_operand(
+                        block,
+                        scope,
+                        source,
+                        LocalInfo::Boring,
+                        NeedsTemporary::Maybe
+                    )
+                );
+                block.and(Rvalue::WrapUnsafeBinder(source, expr.ty))
+            }
+
             ExprKind::Yield { .. }
             | ExprKind::Block { .. }
             | ExprKind::Match { .. }
@@ -532,7 +545,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::Become { .. }
             | ExprKind::InlineAsm { .. }
             | ExprKind::PlaceTypeAscription { .. }
-            | ExprKind::ValueTypeAscription { .. } => {
+            | ExprKind::ValueTypeAscription { .. }
+            | ExprKind::PlaceUnwrapUnsafeBinder { .. }
+            | ExprKind::ValueUnwrapUnsafeBinder { .. } => {
                 // these do not have corresponding `Rvalue` variants,
                 // so make an operand and then return that
                 debug_assert!(!matches!(
diff --git a/compiler/rustc_mir_build/src/builder/expr/category.rs b/compiler/rustc_mir_build/src/builder/expr/category.rs
index e0349e3e3f6..ca55d36bfc6 100644
--- a/compiler/rustc_mir_build/src/builder/expr/category.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/category.rs
@@ -41,7 +41,9 @@ impl Category {
             | ExprKind::UpvarRef { .. }
             | ExprKind::VarRef { .. }
             | ExprKind::PlaceTypeAscription { .. }
-            | ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
+            | ExprKind::ValueTypeAscription { .. }
+            | ExprKind::PlaceUnwrapUnsafeBinder { .. }
+            | ExprKind::ValueUnwrapUnsafeBinder { .. } => Some(Category::Place),
 
             ExprKind::LogicalOp { .. }
             | ExprKind::Match { .. }
@@ -68,7 +70,8 @@ impl Category {
             | ExprKind::Assign { .. }
             | ExprKind::AssignOp { .. }
             | ExprKind::ThreadLocalRef(_)
-            | ExprKind::OffsetOf { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
+            | ExprKind::OffsetOf { .. }
+            | ExprKind::WrapUnsafeBinder { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
 
             ExprKind::ConstBlock { .. }
             | ExprKind::Literal { .. }
diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs
index 928156572d5..b25cd0f4426 100644
--- a/compiler/rustc_mir_build/src/builder/expr/into.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/into.rs
@@ -554,7 +554,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             ExprKind::VarRef { .. }
             | ExprKind::UpvarRef { .. }
             | ExprKind::PlaceTypeAscription { .. }
-            | ExprKind::ValueTypeAscription { .. } => {
+            | ExprKind::ValueTypeAscription { .. }
+            | ExprKind::PlaceUnwrapUnsafeBinder { .. }
+            | ExprKind::ValueUnwrapUnsafeBinder { .. } => {
                 debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
 
                 let place = unpack!(block = this.as_place(block, expr_id));
@@ -613,7 +615,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::ConstParam { .. }
             | ExprKind::ThreadLocalRef(_)
             | ExprKind::StaticRef { .. }
-            | ExprKind::OffsetOf { .. } => {
+            | ExprKind::OffsetOf { .. }
+            | ExprKind::WrapUnsafeBinder { .. } => {
                 debug_assert!(match Category::of(&expr.kind).unwrap() {
                     // should be handled above
                     Category::Rvalue(RvalueFunc::Into) => false,
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index 8cca84d7fcc..afe6b4475be 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -141,43 +141,49 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.cfg.terminate(block, self.source_info(match_start_span), terminator);
             }
 
-            TestKind::Eq { value, ty } => {
+            TestKind::Eq { value, mut ty } => {
                 let tcx = self.tcx;
                 let success_block = target_block(TestBranch::Success);
                 let fail_block = target_block(TestBranch::Failure);
-                if let ty::Adt(def, _) = ty.kind()
-                    && tcx.is_lang_item(def.did(), LangItem::String)
-                {
-                    if !tcx.features().string_deref_patterns() {
-                        span_bug!(
+
+                let expect_ty = value.ty();
+                let expect = self.literal_operand(test.span, value);
+
+                let mut place = place;
+                let mut block = block;
+                match ty.kind() {
+                    ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => {
+                        if !tcx.features().string_deref_patterns() {
+                            span_bug!(
+                                test.span,
+                                "matching on `String` went through without enabling string_deref_patterns"
+                            );
+                        }
+                        let re_erased = tcx.lifetimes.re_erased;
+                        let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
+                        let ref_str = self.temp(ref_str_ty, test.span);
+                        let eq_block = self.cfg.start_new_block();
+                        // `let ref_str: &str = <String as Deref>::deref(&place);`
+                        self.call_deref(
+                            block,
+                            eq_block,
+                            place,
+                            Mutability::Not,
+                            ty,
+                            ref_str,
                             test.span,
-                            "matching on `String` went through without enabling string_deref_patterns"
                         );
+                        // Since we generated a `ref_str = <String as Deref>::deref(&place) -> eq_block` terminator,
+                        // we need to add all further statements to `eq_block`.
+                        // Similarly, the normal test code should be generated for the `&str`, instead of the `String`.
+                        block = eq_block;
+                        place = ref_str;
+                        ty = ref_str_ty;
                     }
-                    let re_erased = tcx.lifetimes.re_erased;
-                    let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
-                    let ref_str = self.temp(ref_str_ty, test.span);
-                    let eq_block = self.cfg.start_new_block();
-                    // `let ref_str: &str = <String as Deref>::deref(&place);`
-                    self.call_deref(
-                        block,
-                        eq_block,
-                        place,
-                        Mutability::Not,
-                        ty,
-                        ref_str,
-                        test.span,
-                    );
-                    self.non_scalar_compare(
-                        eq_block,
-                        success_block,
-                        fail_block,
-                        source_info,
-                        value,
-                        ref_str,
-                        ref_str_ty,
-                    );
-                } else if !ty.is_scalar() {
+                    _ => {}
+                }
+
+                if !ty.is_scalar() {
                     // Use `PartialEq::eq` instead of `BinOp::Eq`
                     // (the binop can only handle primitives)
                     self.non_scalar_compare(
@@ -185,14 +191,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         success_block,
                         fail_block,
                         source_info,
-                        value,
-                        place,
+                        expect,
+                        expect_ty,
+                        Operand::Copy(place),
                         ty,
                     );
                 } else {
-                    assert_eq!(value.ty(), ty);
-                    let expect = self.literal_operand(test.span, value);
-                    let val = Operand::Copy(place);
+                    assert_eq!(expect_ty, ty);
                     self.compare(
                         block,
                         success_block,
@@ -200,7 +205,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         source_info,
                         BinOp::Eq,
                         expect,
-                        val,
+                        Operand::Copy(place),
                     );
                 }
             }
@@ -371,12 +376,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         success_block: BasicBlock,
         fail_block: BasicBlock,
         source_info: SourceInfo,
-        value: Const<'tcx>,
-        mut val: Place<'tcx>,
+        mut expect: Operand<'tcx>,
+        expect_ty: Ty<'tcx>,
+        mut val: Operand<'tcx>,
         mut ty: Ty<'tcx>,
     ) {
-        let mut expect = self.literal_operand(source_info.span, value);
-
         // If we're using `b"..."` as a pattern, we need to insert an
         // unsizing coercion, as the byte string has the type `&[u8; N]`.
         //
@@ -391,7 +395,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             _ => None,
         };
         let opt_ref_ty = unsize(ty);
-        let opt_ref_test_ty = unsize(value.ty());
+        let opt_ref_test_ty = unsize(expect_ty);
         match (opt_ref_ty, opt_ref_test_ty) {
             // nothing to do, neither is an array
             (None, None) => {}
@@ -410,11 +414,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 PointerCoercion::Unsize,
                                 CoercionSource::Implicit,
                             ),
-                            Operand::Copy(val),
+                            val,
                             ty,
                         ),
                     );
-                    val = temp;
+                    val = Operand::Copy(temp);
                 }
                 if opt_ref_test_ty.is_some() {
                     let slice = self.temp(ty, source_info.span);
@@ -470,11 +474,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 const_: method,
             })),
-            args: [Spanned { node: Operand::Copy(val), span: DUMMY_SP }, Spanned {
-                node: expect,
-                span: DUMMY_SP,
-            }]
-            .into(),
+            args: [Spanned { node: val, span: DUMMY_SP }, Spanned { node: expect, span: DUMMY_SP }]
+                .into(),
             destination: eq_result,
             target: Some(eq_block),
             unwind: UnwindAction::Continue,
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 9fa431f7d5f..e04c70b5883 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -20,7 +20,6 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
-use rustc_middle::query::TyCtxtAt;
 use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir};
 use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
@@ -45,10 +44,10 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
         .collect()
 }
 
-/// Construct the MIR for a given `DefId`.
-pub(crate) fn build_mir<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> {
-    let tcx = tcx.tcx;
-    tcx.ensure_with_value().thir_abstract_const(def);
+/// Create the MIR for a given `DefId`, including unreachable code. Do not call
+/// this directly; instead use the cached version via `mir_built`.
+pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
+    tcx.ensure_done().thir_abstract_const(def);
     if let Err(e) = tcx.check_match(def) {
         return construct_error(tcx, def, e);
     }
@@ -69,7 +68,7 @@ pub(crate) fn build_mir<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx
             // "not all control paths return a value" is reported here.
             //
             // maybe move the check to a MIR pass?
-            tcx.ensure().check_liveness(def);
+            tcx.ensure_ok().check_liveness(def);
 
             // Don't steal here, instead steal in unsafeck. This is so that
             // pattern inline constants can be evaluated as part of building the
diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs
index 0659e3ea314..921205428db 100644
--- a/compiler/rustc_mir_build/src/check_tail_calls.rs
+++ b/compiler/rustc_mir_build/src/check_tail_calls.rs
@@ -1,4 +1,5 @@
 use rustc_abi::ExternAbi;
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem;
 use rustc_hir::def::DefKind;
@@ -344,12 +345,14 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for TailCallCkVisitor<'a, 'tcx> {
     }
 
     fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
-        if let ExprKind::Become { value } = expr.kind {
-            let call = &self.thir[value];
-            self.check_tail_call(call, expr);
-        }
+        ensure_sufficient_stack(|| {
+            if let ExprKind::Become { value } = expr.kind {
+                let call = &self.thir[value];
+                self.check_tail_call(call, expr);
+            }
 
-        visit::walk_expr(self, expr);
+            visit::walk_expr(self, expr);
+        });
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 995bc311b7c..b6494173b0f 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -2,6 +2,7 @@ use std::borrow::Cow;
 use std::mem;
 use std::ops::Bound;
 
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::DiagArgValue;
 use rustc_hir::def::DefKind;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
@@ -200,7 +201,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
     fn visit_inner_body(&mut self, def: LocalDefId) {
         if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
             // Runs all other queries that depend on THIR.
-            self.tcx.ensure_with_value().mir_built(def);
+            self.tcx.ensure_done().mir_built(def);
             let inner_thir = &inner_thir.steal();
             let hir_context = self.tcx.local_def_id_to_hir_id(def);
             let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe);
@@ -439,6 +440,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             | ExprKind::NeverToAny { .. }
             | ExprKind::PlaceTypeAscription { .. }
             | ExprKind::ValueTypeAscription { .. }
+            | ExprKind::PlaceUnwrapUnsafeBinder { .. }
+            | ExprKind::ValueUnwrapUnsafeBinder { .. }
+            | ExprKind::WrapUnsafeBinder { .. }
             | ExprKind::PointerCoercion { .. }
             | ExprKind::Repeat { .. }
             | ExprKind::StaticRef { .. }
@@ -473,7 +477,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => {
                 let prev_id = self.hir_context;
                 self.hir_context = hir_id;
-                self.visit_expr(&self.thir[value]);
+                ensure_sufficient_stack(|| {
+                    self.visit_expr(&self.thir[value]);
+                });
                 self.hir_context = prev_id;
                 return; // don't visit the whole expression
             }
@@ -680,6 +686,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     }
                 }
             }
+            ExprKind::PlaceUnwrapUnsafeBinder { .. }
+            | ExprKind::ValueUnwrapUnsafeBinder { .. }
+            | ExprKind::WrapUnsafeBinder { .. } => {
+                self.requires_unsafe(expr.span, UnsafeBinderCast);
+            }
             _ => {}
         }
         visit::walk_expr(self, expr);
@@ -728,6 +739,7 @@ enum UnsafeOpKind {
         /// (e.g., with `-C target-feature`).
         build_enabled: Vec<Symbol>,
     },
+    UnsafeBinderCast,
 }
 
 use UnsafeOpKind::*;
@@ -891,6 +903,15 @@ impl UnsafeOpKind {
                     unsafe_not_inherited_note,
                 },
             ),
+            UnsafeBinderCast => tcx.emit_node_span_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
+                    span,
+                    unsafe_not_inherited_note,
+                },
+            ),
         }
     }
 
@@ -1099,6 +1120,15 @@ impl UnsafeOpKind {
                     function: tcx.def_path_str(*function),
                 });
             }
+            UnsafeBinderCast if unsafe_op_in_unsafe_fn_allowed => {
+                dcx.emit_err(UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                    span,
+                    unsafe_not_inherited_note,
+                });
+            }
+            UnsafeBinderCast => {
+                dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note });
+            }
         }
     }
 }
@@ -1112,7 +1142,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
 
     let Ok((thir, expr)) = tcx.thir_body(def) else { return };
     // Runs all other queries that depend on THIR.
-    tcx.ensure_with_value().mir_built(def);
+    tcx.ensure_done().mir_built(def);
     let thir = &thir.steal();
 
     let hir_id = tcx.local_def_id_to_hir_id(def);
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 1f87bf0dbbb..af6f33d9cdd 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -161,6 +161,18 @@ pub(crate) struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe
 }
 
 #[derive(LintDiagnostic)]
+#[diag(
+    mir_build_unsafe_binder_cast_requires_unsafe,
+    code = E0133,
+)]
+pub(crate) struct UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
+    #[label]
+    pub(crate) span: Span,
+    #[subdiagnostic]
+    pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe, code = E0133)]
 #[help]
 pub(crate) struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
@@ -494,6 +506,32 @@ pub(crate) struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
 }
 
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_unsafe_binder_cast_requires_unsafe,
+    code = E0133,
+)]
+pub(crate) struct UnsafeBinderCastRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    #[subdiagnostic]
+    pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = E0133,
+)]
+pub(crate) struct UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    #[subdiagnostic]
+    pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
+}
+
 #[derive(Subdiagnostic)]
 #[label(mir_build_unsafe_not_inherited)]
 pub(crate) struct UnsafeNotInheritedNote {
@@ -801,10 +839,6 @@ pub(crate) struct BorrowOfMovedValue {
     pub(crate) ty: String,
     #[suggestion(code = "ref ", applicability = "machine-applicable")]
     pub(crate) suggest_borrowing: Option<Span>,
-    #[note(mir_build_full_type_name)]
-    #[note(mir_build_consider_verbose)]
-    pub(crate) has_path: bool,
-    pub(crate) path: String,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 8e786733ee0..fa5db32d913 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -14,11 +14,11 @@
 // The `builder` module used to be named `build`, but that was causing GitHub's
 // "Go to file" feature to silently ignore all files in the module, probably
 // because it assumes that "build" is a build-output directory. See #134365.
-mod builder;
+pub mod builder;
 mod check_tail_calls;
 mod check_unsafety;
 mod errors;
-mod thir;
+pub mod thir;
 
 use rustc_middle::util::Providers;
 
@@ -27,12 +27,9 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 pub fn provide(providers: &mut Providers) {
     providers.check_match = thir::pattern::check_match;
     providers.lit_to_const = thir::constant::lit_to_const;
-    providers.hooks.build_mir = builder::build_mir;
     providers.closure_saved_names_of_captured_variables =
         builder::closure_saved_names_of_captured_variables;
     providers.check_unsafety = check_unsafety::check_unsafety;
     providers.check_tail_calls = check_tail_calls::check_tail_calls;
     providers.thir_body = thir::cx::thir_body;
-    providers.hooks.thir_tree = thir::print::thir_tree;
-    providers.hooks.thir_flat = thir::print::thir_flat;
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 9cdf08d749b..795ac6b4bea 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -1,5 +1,6 @@
 use itertools::Itertools;
 use rustc_abi::{FIRST_VARIANT, FieldIdx};
+use rustc_ast::UnsafeBinderCastKind;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -910,8 +911,19 @@ impl<'tcx> Cx<'tcx> {
                 }
             }
 
-            hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => {
-                unreachable!("unsafe binders are not yet implemented")
+            hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, source, _ty) => {
+                // FIXME(unsafe_binders): Take into account the ascribed type, too.
+                let mirrored = self.mirror_expr(source);
+                if source.is_syntactic_place_expr() {
+                    ExprKind::PlaceUnwrapUnsafeBinder { source: mirrored }
+                } else {
+                    ExprKind::ValueUnwrapUnsafeBinder { source: mirrored }
+                }
+            }
+            hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, source, _ty) => {
+                // FIXME(unsafe_binders): Take into account the ascribed type, too.
+                let mirrored = self.mirror_expr(source);
+                ExprKind::WrapUnsafeBinder { source: mirrored }
             }
 
             hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index ca26cc13b5e..c7c88801d4d 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -7,5 +7,5 @@
 pub(crate) mod constant;
 pub(crate) mod cx;
 pub(crate) mod pattern;
-pub(crate) mod print;
+pub mod print;
 mod util;
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 e0a1117f905..8247a6c6a32 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -326,9 +326,10 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             | Use { source }
             | PointerCoercion { source, .. }
             | PlaceTypeAscription { source, .. }
-            | ValueTypeAscription { source, .. } => {
-                self.is_known_valid_scrutinee(&self.thir()[*source])
-            }
+            | ValueTypeAscription { source, .. }
+            | PlaceUnwrapUnsafeBinder { source }
+            | ValueUnwrapUnsafeBinder { source }
+            | WrapUnsafeBinder { source } => self.is_known_valid_scrutinee(&self.thir()[*source]),
 
             // These diverge.
             Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true,
@@ -796,16 +797,16 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
             });
             if !conflicts_ref.is_empty() {
                 let mut path = None;
-                let ty = cx.tcx.short_ty_string(ty, &mut path);
-                sess.dcx().emit_err(BorrowOfMovedValue {
+                let ty = cx.tcx.short_string(ty, &mut path);
+                let mut err = sess.dcx().create_err(BorrowOfMovedValue {
                     binding_span: pat.span,
                     conflicts_ref,
                     name: Ident::new(name, pat.span),
                     ty,
                     suggest_borrowing: Some(pat.span.shrink_to_lo()),
-                    has_path: path.is_some(),
-                    path: path.map(|p| p.display().to_string()).unwrap_or_default(),
                 });
+                *err.long_ty_path() = path;
+                err.emit();
             }
             return;
         }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 3853b95f78b..cc6d69710e4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -46,7 +46,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         match c.kind() {
             ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
-            ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty),
+            ty::ConstKind::Value(cv) => convert.valtree_to_pat(cv.valtree, cv.ty),
             _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
         }
     }
@@ -214,6 +214,7 @@ impl<'tcx> ConstToPat<'tcx> {
     }
 
     // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
+    // FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately.
     #[instrument(skip(self), level = "debug")]
     fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
         let span = self.span;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 44b038bb5fa..20a728d6d5b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -332,10 +332,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     .unwrap_or_else(PatKind::Error)
             }
 
-            hir::PatKind::Path(ref qpath) => {
-                return self.lower_path(qpath, pat.hir_id, pat.span);
-            }
-
             hir::PatKind::Deref(subpattern) => {
                 let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern);
                 let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 2bcdb67c58a..729c8f784ba 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -1,12 +1,13 @@
 use std::fmt::{self, Write};
 
-use rustc_middle::query::TyCtxtAt;
 use rustc_middle::thir::*;
 use rustc_middle::ty;
+use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::LocalDefId;
 
-pub(crate) fn thir_tree(tcx: TyCtxtAt<'_>, owner_def: LocalDefId) -> String {
-    match super::cx::thir_body(*tcx, owner_def) {
+/// Create a THIR tree for debugging.
+pub fn thir_tree(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String {
+    match super::cx::thir_body(tcx, owner_def) {
         Ok((thir, _)) => {
             let thir = thir.steal();
             let mut printer = ThirPrinter::new(&thir);
@@ -17,8 +18,9 @@ pub(crate) fn thir_tree(tcx: TyCtxtAt<'_>, owner_def: LocalDefId) -> String {
     }
 }
 
-pub(crate) fn thir_flat(tcx: TyCtxtAt<'_>, owner_def: LocalDefId) -> String {
-    match super::cx::thir_body(*tcx, owner_def) {
+/// Create a list-like THIR representation for debugging.
+pub fn thir_flat(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String {
+    match super::cx::thir_body(tcx, owner_def) {
         Ok((thir, _)) => format!("{:#?}", thir.steal()),
         Err(_) => "error".into(),
     }
@@ -475,6 +477,24 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_expr(*source, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl);
             }
+            PlaceUnwrapUnsafeBinder { source } => {
+                print_indented!(self, "PlaceUnwrapUnsafeBinder {", depth_lvl);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            ValueUnwrapUnsafeBinder { source } => {
+                print_indented!(self, "ValueUnwrapUnsafeBinder {", depth_lvl);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
+            WrapUnsafeBinder { source } => {
+                print_indented!(self, "WrapUnsafeBinder {", depth_lvl);
+                print_indented!(self, "source:", depth_lvl + 1);
+                self.print_expr(*source, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
             Closure(closure_expr) => {
                 print_indented!(self, "Closure {", depth_lvl);
                 print_indented!(self, "closure_expr:", depth_lvl + 1);
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index df4b1a53417..9abb8343432 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -97,7 +97,8 @@ where
             | Rvalue::UnaryOp(..)
             | Rvalue::Discriminant(..)
             | Rvalue::Aggregate(..)
-            | Rvalue::CopyForDeref(..) => {}
+            | Rvalue::CopyForDeref(..)
+            | Rvalue::WrapUnsafeBinder(..) => {}
         }
     }
 
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
index d79d2c316ee..d056ad3d4b4 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
@@ -32,6 +32,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
             }
             ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u),
             ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()),
+            ProjectionElem::UnwrapUnsafeBinder(_ty) => ProjectionElem::UnwrapUnsafeBinder(()),
         }
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index d1b3a389e9e..6e00e427a46 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -208,7 +208,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
                     | ty::Infer(_)
                     | ty::Error(_)
                     | ty::Placeholder(_) => bug!(
-                        "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
+                        "When Place contains ProjectionElem::Field its type shouldn't be {place_ty:#?}"
                     ),
                 },
                 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
@@ -226,6 +226,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
                     }
                     _ => bug!("Unexpected type {place_ty:#?}"),
                 },
+                ProjectionElem::UnwrapUnsafeBinder(_) => {}
                 // `OpaqueCast`:Only transmutes the type, so no moves there.
                 // `Downcast`  :Only changes information about a `Place` without moving.
                 // `Subtype`   :Only transmutes the type, so moves.
@@ -399,7 +400,8 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::Cast(_, ref operand, _)
             | Rvalue::ShallowInitBox(ref operand, _)
-            | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand),
+            | Rvalue::UnaryOp(_, ref operand)
+            | Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand),
             Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
                 self.gather_operand(lhs);
                 self.gather_operand(rhs);
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index d7e22c12394..ca5564e447a 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -1,11 +1,10 @@
-use rustc_hir::lang_items::LangItem;
 use rustc_index::IndexVec;
 use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_session::Session;
-use tracing::{debug, trace};
+
+use crate::check_pointers::{BorrowCheckMode, PointerCheck, check_pointers};
 
 pub(super) struct CheckAlignment;
 
@@ -19,46 +18,19 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // This pass emits new panics. If for whatever reason we do not have a panic
-        // implementation, running this pass may cause otherwise-valid code to not compile.
-        if tcx.lang_items().get(LangItem::PanicImpl).is_none() {
-            return;
-        }
-
-        let typing_env = body.typing_env(tcx);
-        let basic_blocks = body.basic_blocks.as_mut();
-        let local_decls = &mut body.local_decls;
-
-        // This pass inserts new blocks. Each insertion changes the Location for all
-        // statements/blocks after. Iterating or visiting the MIR in order would require updating
-        // our current location after every insertion. By iterating backwards, we dodge this issue:
-        // The only Locations that an insertion changes have already been handled.
-        for block in (0..basic_blocks.len()).rev() {
-            let block = block.into();
-            for statement_index in (0..basic_blocks[block].statements.len()).rev() {
-                let location = Location { block, statement_index };
-                let statement = &basic_blocks[block].statements[statement_index];
-                let source_info = statement.source_info;
-
-                let mut finder =
-                    PointerFinder { tcx, local_decls, typing_env, pointers: Vec::new() };
-                finder.visit_statement(statement, location);
-
-                for (local, ty) in finder.pointers {
-                    debug!("Inserting alignment check for {:?}", ty);
-                    let new_block = split_block(basic_blocks, location);
-                    insert_alignment_check(
-                        tcx,
-                        local_decls,
-                        &mut basic_blocks[block],
-                        local,
-                        ty,
-                        source_info,
-                        new_block,
-                    );
-                }
-            }
-        }
+        // Skip trivially aligned place types.
+        let excluded_pointees = [tcx.types.bool, tcx.types.i8, tcx.types.u8];
+
+        // We have to exclude borrows here: in `&x.field`, the exact
+        // requirement is that the final reference must be aligned, but
+        // `check_pointers` would check that `x` is aligned, which would be wrong.
+        check_pointers(
+            tcx,
+            body,
+            &excluded_pointees,
+            insert_alignment_check,
+            BorrowCheckMode::ExcludeBorrows,
+        );
     }
 
     fn is_required(&self) -> bool {
@@ -66,119 +38,33 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
     }
 }
 
-struct PointerFinder<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    local_decls: &'a mut LocalDecls<'tcx>,
-    typing_env: ty::TypingEnv<'tcx>,
-    pointers: Vec<(Place<'tcx>, Ty<'tcx>)>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> {
-    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
-        // We want to only check reads and writes to Places, so we specifically exclude
-        // Borrow and RawBorrow.
-        match context {
-            PlaceContext::MutatingUse(
-                MutatingUseContext::Store
-                | MutatingUseContext::AsmOutput
-                | MutatingUseContext::Call
-                | MutatingUseContext::Yield
-                | MutatingUseContext::Drop,
-            ) => {}
-            PlaceContext::NonMutatingUse(
-                NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
-            ) => {}
-            _ => {
-                return;
-            }
-        }
-
-        if !place.is_indirect() {
-            return;
-        }
-
-        // Since Deref projections must come first and only once, the pointer for an indirect place
-        // is the Local that the Place is based on.
-        let pointer = Place::from(place.local);
-        let pointer_ty = self.local_decls[place.local].ty;
-
-        // We only want to check places based on unsafe pointers
-        if !pointer_ty.is_unsafe_ptr() {
-            trace!("Indirect, but not based on an unsafe ptr, not checking {:?}", place);
-            return;
-        }
-
-        let pointee_ty =
-            pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer");
-        // Ideally we'd support this in the future, but for now we are limited to sized types.
-        if !pointee_ty.is_sized(self.tcx, self.typing_env) {
-            debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty);
-            return;
-        }
-
-        // Try to detect types we are sure have an alignment of 1 and skip the check
-        // We don't need to look for str and slices, we already rejected unsized types above
-        let element_ty = match pointee_ty.kind() {
-            ty::Array(ty, _) => *ty,
-            _ => pointee_ty,
-        };
-        if [self.tcx.types.bool, self.tcx.types.i8, self.tcx.types.u8].contains(&element_ty) {
-            debug!("Trivially aligned place type: {:?}", pointee_ty);
-            return;
-        }
-
-        // Ensure that this place is based on an aligned pointer.
-        self.pointers.push((pointer, pointee_ty));
-
-        self.super_place(place, context, location);
-    }
-}
-
-fn split_block(
-    basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
-    location: Location,
-) -> BasicBlock {
-    let block_data = &mut basic_blocks[location.block];
-
-    // Drain every statement after this one and move the current terminator to a new basic block
-    let new_block = BasicBlockData {
-        statements: block_data.statements.split_off(location.statement_index),
-        terminator: block_data.terminator.take(),
-        is_cleanup: block_data.is_cleanup,
-    };
-
-    basic_blocks.push(new_block)
-}
-
+/// Inserts the actual alignment check's logic. Returns a
+/// [AssertKind::MisalignedPointerDereference] on failure.
 fn insert_alignment_check<'tcx>(
     tcx: TyCtxt<'tcx>,
-    local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
-    block_data: &mut BasicBlockData<'tcx>,
     pointer: Place<'tcx>,
     pointee_ty: Ty<'tcx>,
+    local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
+    stmts: &mut Vec<Statement<'tcx>>,
     source_info: SourceInfo,
-    new_block: BasicBlock,
-) {
-    // Cast the pointer to a *const ()
+) -> PointerCheck<'tcx> {
+    // Cast the pointer to a *const ().
     let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
     let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
     let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
-    block_data
-        .statements
+    stmts
         .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) });
 
-    // Transmute the pointer to a usize (equivalent to `ptr.addr()`)
+    // Transmute the pointer to a usize (equivalent to `ptr.addr()`).
     let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
     let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
-    block_data
-        .statements
-        .push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
+    stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
 
     // Get the alignment of the pointee
     let alignment =
         local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
     let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty);
-    block_data.statements.push(Statement {
+    stmts.push(Statement {
         source_info,
         kind: StatementKind::Assign(Box::new((alignment, rvalue))),
     });
@@ -191,7 +77,7 @@ fn insert_alignment_check<'tcx>(
         user_ty: None,
         const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize),
     }));
-    block_data.statements.push(Statement {
+    stmts.push(Statement {
         source_info,
         kind: StatementKind::Assign(Box::new((
             alignment_mask,
@@ -202,7 +88,7 @@ fn insert_alignment_check<'tcx>(
     // BitAnd the alignment mask with the pointer
     let alignment_bits =
         local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
-    block_data.statements.push(Statement {
+    stmts.push(Statement {
         source_info,
         kind: StatementKind::Assign(Box::new((
             alignment_bits,
@@ -220,7 +106,7 @@ fn insert_alignment_check<'tcx>(
         user_ty: None,
         const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize),
     }));
-    block_data.statements.push(Statement {
+    stmts.push(Statement {
         source_info,
         kind: StatementKind::Assign(Box::new((
             is_ok,
@@ -228,21 +114,13 @@ fn insert_alignment_check<'tcx>(
         ))),
     });
 
-    // Set this block's terminator to our assert, continuing to new_block if we pass
-    block_data.terminator = Some(Terminator {
-        source_info,
-        kind: TerminatorKind::Assert {
-            cond: Operand::Copy(is_ok),
-            expected: true,
-            target: new_block,
-            msg: Box::new(AssertKind::MisalignedPointerDereference {
-                required: Operand::Copy(alignment),
-                found: Operand::Copy(addr),
-            }),
-            // This calls panic_misaligned_pointer_dereference, which is #[rustc_nounwind].
-            // We never want to insert an unwind into unsafe code, because unwinding could
-            // make a failing UB check turn into much worse UB when we start unwinding.
-            unwind: UnwindAction::Unreachable,
-        },
-    });
+    // Emit a check that asserts on the alignment and otherwise triggers a
+    // AssertKind::MisalignedPointerDereference.
+    PointerCheck {
+        cond: Operand::Copy(is_ok),
+        assert_kind: Box::new(AssertKind::MisalignedPointerDereference {
+            required: Operand::Copy(alignment),
+            found: Operand::Copy(addr),
+        }),
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 7968b666dff..3affe4abbfa 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
                 // the `self` parameter of a method call (as the terminator of our current
                 // BasicBlock). If so, we emit a more specific lint.
                 let method_did = self.target_local.and_then(|target_local| {
-                    rustc_middle::util::find_self_call(self.tcx, self.body, target_local, loc.block)
+                    find_self_call(self.tcx, self.body, target_local, loc.block)
                 });
                 let lint_loc =
                     if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
diff --git a/compiler/rustc_mir_transform/src/check_null.rs b/compiler/rustc_mir_transform/src/check_null.rs
new file mode 100644
index 00000000000..0b6c0ceaac1
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/check_null.rs
@@ -0,0 +1,110 @@
+use rustc_index::IndexVec;
+use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_session::Session;
+
+use crate::check_pointers::{BorrowCheckMode, PointerCheck, check_pointers};
+
+pub(super) struct CheckNull;
+
+impl<'tcx> crate::MirPass<'tcx> for CheckNull {
+    fn is_enabled(&self, sess: &Session) -> bool {
+        sess.ub_checks()
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        check_pointers(tcx, body, &[], insert_null_check, BorrowCheckMode::IncludeBorrows);
+    }
+
+    fn is_required(&self) -> bool {
+        true
+    }
+}
+
+fn insert_null_check<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    pointer: Place<'tcx>,
+    pointee_ty: Ty<'tcx>,
+    local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
+    stmts: &mut Vec<Statement<'tcx>>,
+    source_info: SourceInfo,
+) -> PointerCheck<'tcx> {
+    // Cast the pointer to a *const ().
+    let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
+    let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
+    let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
+    stmts
+        .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) });
+
+    // Transmute the pointer to a usize (equivalent to `ptr.addr()`).
+    let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
+    let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
+    stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
+
+    // Get size of the pointee (zero-sized reads and writes are allowed).
+    let rvalue = Rvalue::NullaryOp(NullOp::SizeOf, pointee_ty);
+    let sizeof_pointee =
+        local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
+    stmts.push(Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((sizeof_pointee, rvalue))),
+    });
+
+    // Check that the pointee is not a ZST.
+    let zero = Operand::Constant(Box::new(ConstOperand {
+        span: source_info.span,
+        user_ty: None,
+        const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize),
+    }));
+    let is_pointee_no_zst =
+        local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
+    stmts.push(Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((
+            is_pointee_no_zst,
+            Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(sizeof_pointee), zero.clone()))),
+        ))),
+    });
+
+    // Check whether the pointer is null.
+    let is_null = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
+    stmts.push(Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((
+            is_null,
+            Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(addr), zero))),
+        ))),
+    });
+
+    // We want to throw an exception if the pointer is null and doesn't point to a ZST.
+    let should_throw_exception =
+        local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
+    stmts.push(Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((
+            should_throw_exception,
+            Rvalue::BinaryOp(
+                BinOp::BitAnd,
+                Box::new((Operand::Copy(is_null), Operand::Copy(is_pointee_no_zst))),
+            ),
+        ))),
+    });
+
+    // The final condition whether this pointer usage is ok or not.
+    let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
+    stmts.push(Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((
+            is_ok,
+            Rvalue::UnaryOp(UnOp::Not, Operand::Copy(should_throw_exception)),
+        ))),
+    });
+
+    // Emit a PointerCheck that asserts on the condition and otherwise triggers
+    // a AssertKind::NullPointerDereference.
+    PointerCheck {
+        cond: Operand::Copy(is_ok),
+        assert_kind: Box::new(AssertKind::NullPointerDereference),
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs
new file mode 100644
index 00000000000..72460542f87
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/check_pointers.rs
@@ -0,0 +1,234 @@
+use rustc_hir::lang_items::LangItem;
+use rustc_index::IndexVec;
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use tracing::{debug, trace};
+
+/// Details of a pointer check, the condition on which we decide whether to
+/// fail the assert and an [AssertKind] that defines the behavior on failure.
+pub(crate) struct PointerCheck<'tcx> {
+    pub(crate) cond: Operand<'tcx>,
+    pub(crate) assert_kind: Box<AssertKind<Operand<'tcx>>>,
+}
+
+/// Indicates whether we insert the checks for borrow places of a raw pointer.
+/// Concretely places with [MutatingUseContext::Borrow] or
+/// [NonMutatingUseContext::SharedBorrow].
+#[derive(Copy, Clone)]
+pub(crate) enum BorrowCheckMode {
+    IncludeBorrows,
+    ExcludeBorrows,
+}
+
+/// Utility for adding a check for read/write on every sized, raw pointer.
+///
+/// Visits every read/write access to a [Sized], raw pointer and inserts a
+/// new basic block directly before the pointer access. (Read/write accesses
+/// are determined by the `PlaceContext` of the MIR visitor.) Then calls
+/// `on_finding` to insert the actual logic for a pointer check (e.g. check for
+/// alignment). A check can choose to be inserted for (mutable) borrows of
+/// raw pointers via the `borrow_check_mode` parameter.
+///
+/// This utility takes care of the right order of blocks, the only thing a
+/// caller must do in `on_finding` is:
+/// - Append [Statement]s to `stmts`.
+/// - Append [LocalDecl]s to `local_decls`.
+/// - Return a [PointerCheck] that contains the condition and an [AssertKind].
+///   The AssertKind must be a panic with `#[rustc_nounwind]`. The condition
+///   should always return the boolean `is_ok`, so evaluate to true in case of
+///   success and fail the check otherwise.
+/// This utility will insert a terminator block that asserts on the condition
+/// and panics on failure.
+pub(crate) fn check_pointers<'a, 'tcx, F>(
+    tcx: TyCtxt<'tcx>,
+    body: &mut Body<'tcx>,
+    excluded_pointees: &'a [Ty<'tcx>],
+    on_finding: F,
+    borrow_check_mode: BorrowCheckMode,
+) where
+    F: Fn(
+        /* tcx: */ TyCtxt<'tcx>,
+        /* pointer: */ Place<'tcx>,
+        /* pointee_ty: */ Ty<'tcx>,
+        /* local_decls: */ &mut IndexVec<Local, LocalDecl<'tcx>>,
+        /* stmts: */ &mut Vec<Statement<'tcx>>,
+        /* source_info: */ SourceInfo,
+    ) -> PointerCheck<'tcx>,
+{
+    // This pass emits new panics. If for whatever reason we do not have a panic
+    // implementation, running this pass may cause otherwise-valid code to not compile.
+    if tcx.lang_items().get(LangItem::PanicImpl).is_none() {
+        return;
+    }
+
+    let typing_env = body.typing_env(tcx);
+    let basic_blocks = body.basic_blocks.as_mut();
+    let local_decls = &mut body.local_decls;
+
+    // This operation inserts new blocks. Each insertion changes the Location for all
+    // statements/blocks after. Iterating or visiting the MIR in order would require updating
+    // our current location after every insertion. By iterating backwards, we dodge this issue:
+    // The only Locations that an insertion changes have already been handled.
+    for block in (0..basic_blocks.len()).rev() {
+        let block = block.into();
+        for statement_index in (0..basic_blocks[block].statements.len()).rev() {
+            let location = Location { block, statement_index };
+            let statement = &basic_blocks[block].statements[statement_index];
+            let source_info = statement.source_info;
+
+            let mut finder = PointerFinder::new(
+                tcx,
+                local_decls,
+                typing_env,
+                excluded_pointees,
+                borrow_check_mode,
+            );
+            finder.visit_statement(statement, location);
+
+            for (local, ty) in finder.into_found_pointers() {
+                debug!("Inserting check for {:?}", ty);
+                let new_block = split_block(basic_blocks, location);
+
+                // Invoke `on_finding` which appends to `local_decls` and the
+                // blocks statements. It returns information about the assert
+                // we're performing in the Terminator.
+                let block_data = &mut basic_blocks[block];
+                let pointer_check = on_finding(
+                    tcx,
+                    local,
+                    ty,
+                    local_decls,
+                    &mut block_data.statements,
+                    source_info,
+                );
+                block_data.terminator = Some(Terminator {
+                    source_info,
+                    kind: TerminatorKind::Assert {
+                        cond: pointer_check.cond,
+                        expected: true,
+                        target: new_block,
+                        msg: pointer_check.assert_kind,
+                        // This calls a panic function associated with the pointer check, which
+                        // is #[rustc_nounwind]. We never want to insert an unwind into unsafe
+                        // code, because unwinding could make a failing UB check turn into much
+                        // worse UB when we start unwinding.
+                        unwind: UnwindAction::Unreachable,
+                    },
+                });
+            }
+        }
+    }
+}
+
+struct PointerFinder<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    local_decls: &'a mut LocalDecls<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
+    pointers: Vec<(Place<'tcx>, Ty<'tcx>)>,
+    excluded_pointees: &'a [Ty<'tcx>],
+    borrow_check_mode: BorrowCheckMode,
+}
+
+impl<'a, 'tcx> PointerFinder<'a, 'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        local_decls: &'a mut LocalDecls<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
+        excluded_pointees: &'a [Ty<'tcx>],
+        borrow_check_mode: BorrowCheckMode,
+    ) -> Self {
+        PointerFinder {
+            tcx,
+            local_decls,
+            typing_env,
+            excluded_pointees,
+            pointers: Vec::new(),
+            borrow_check_mode,
+        }
+    }
+
+    fn into_found_pointers(self) -> Vec<(Place<'tcx>, Ty<'tcx>)> {
+        self.pointers
+    }
+
+    /// Whether or not we should visit a [Place] with [PlaceContext].
+    ///
+    /// We generally only visit Reads/Writes to a place and only Borrows if
+    /// requested.
+    fn should_visit_place(&self, context: PlaceContext) -> bool {
+        match context {
+            PlaceContext::MutatingUse(
+                MutatingUseContext::Store
+                | MutatingUseContext::Call
+                | MutatingUseContext::Yield
+                | MutatingUseContext::Drop,
+            ) => true,
+            PlaceContext::NonMutatingUse(
+                NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
+            ) => true,
+            PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+            | PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) => {
+                matches!(self.borrow_check_mode, BorrowCheckMode::IncludeBorrows)
+            }
+            _ => false,
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> {
+    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
+        if !self.should_visit_place(context) || !place.is_indirect() {
+            return;
+        }
+
+        // Since Deref projections must come first and only once, the pointer for an indirect place
+        // is the Local that the Place is based on.
+        let pointer = Place::from(place.local);
+        let pointer_ty = self.local_decls[place.local].ty;
+
+        // We only want to check places based on raw pointers
+        if !pointer_ty.is_unsafe_ptr() {
+            trace!("Indirect, but not based on an raw ptr, not checking {:?}", place);
+            return;
+        }
+
+        let pointee_ty =
+            pointer_ty.builtin_deref(true).expect("no builtin_deref for an raw pointer");
+        // Ideally we'd support this in the future, but for now we are limited to sized types.
+        if !pointee_ty.is_sized(self.tcx, self.typing_env) {
+            trace!("Raw pointer, but pointee is not known to be sized: {:?}", pointer_ty);
+            return;
+        }
+
+        // We don't need to look for slices, we already rejected unsized types above.
+        let element_ty = match pointee_ty.kind() {
+            ty::Array(ty, _) => *ty,
+            _ => pointee_ty,
+        };
+        if self.excluded_pointees.contains(&element_ty) {
+            trace!("Skipping pointer for type: {:?}", pointee_ty);
+            return;
+        }
+
+        self.pointers.push((pointer, pointee_ty));
+
+        self.super_place(place, context, location);
+    }
+}
+
+fn split_block(
+    basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+    location: Location,
+) -> BasicBlock {
+    let block_data = &mut basic_blocks[location.block];
+
+    // Drain every statement after this one and move the current terminator to a new basic block.
+    let new_block = BasicBlockData {
+        statements: block_data.statements.split_off(location.statement_index),
+        terminator: block_data.terminator.take(),
+        is_cleanup: block_data.is_cleanup,
+    };
+
+    basic_blocks.push(new_block)
+}
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 5e7b46182dc..a849ed4c3e2 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -6,7 +6,6 @@ use rustc_middle::mir::coverage::{
     FunctionCoverageInfo, MappingKind, Op,
 };
 use rustc_middle::mir::{Body, Statement, StatementKind};
-use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::util::Providers;
 use rustc_span::def_id::LocalDefId;
@@ -15,8 +14,7 @@ use tracing::trace;
 
 /// Registers query/hook implementations related to coverage.
 pub(crate) fn provide(providers: &mut Providers) {
-    providers.hooks.is_eligible_for_coverage =
-        |TyCtxtAt { tcx, .. }, def_id| is_eligible_for_coverage(tcx, def_id);
+    providers.hooks.is_eligible_for_coverage = is_eligible_for_coverage;
     providers.queries.coverage_attr_on = coverage_attr_on;
     providers.queries.coverage_ids_info = coverage_ids_info;
 }
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 8879e029346..90173da17f0 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -504,7 +504,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             | Rvalue::Cast(..)
             | Rvalue::BinaryOp(..)
             | Rvalue::Aggregate(..)
-            | Rvalue::ShallowInitBox(..) => {
+            | Rvalue::ShallowInitBox(..)
+            | Rvalue::WrapUnsafeBinder(..) => {
                 // No modification is possible through these r-values.
                 return ValueOrPlace::TOP;
             }
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 41de1b58b91..7395ad496db 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -575,6 +575,9 @@ impl WriteInfo {
                             self.add_operand(op);
                         }
                     }
+                    Rvalue::WrapUnsafeBinder(op, _) => {
+                        self.add_operand(op);
+                    }
                     Rvalue::ThreadLocalRef(_)
                     | Rvalue::NullaryOp(_, _)
                     | Rvalue::Ref(_, _, _)
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 16e15fa12e0..c261e25100d 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -476,6 +476,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     }
                     ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
                     ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
+                    ProjectionElem::UnwrapUnsafeBinder(ty) => {
+                        ProjectionElem::UnwrapUnsafeBinder(ty)
+                    }
                     // This should have been replaced by a `ConstantIndex` earlier.
                     ProjectionElem::Index(_) => return None,
                 };
@@ -713,6 +716,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
             ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
             ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
+            ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
         };
 
         Some(self.insert(Value::Projection(value, proj)))
@@ -867,6 +871,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 self.simplify_place_projection(place, location);
                 return self.new_pointer(*place, AddressKind::Address(mutbl));
             }
+            Rvalue::WrapUnsafeBinder(ref mut op, _) => {
+                return self.simplify_operand(op, location);
+            }
 
             // Operations.
             Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
@@ -931,6 +938,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
             ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx),
             ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx),
+            ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
         })
     }
 
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 95aeccfdda6..f8b0688dfdc 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -4,7 +4,7 @@ use std::iter;
 use std::ops::{Range, RangeFrom};
 
 use rustc_abi::{ExternAbi, FieldIdx};
-use rustc_attr_parsing::InlineAttr;
+use rustc_attr_parsing::{InlineAttr, OptimizeAttr};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_index::Idx;
@@ -770,6 +770,10 @@ fn check_codegen_attributes<'tcx, I: Inliner<'tcx>>(
         return Err("never inline attribute");
     }
 
+    if let OptimizeAttr::DoNotOptimize = callee_attrs.optimize {
+        return Err("has DoNotOptimize attribute");
+    }
+
     // Reachability pass defines which functions are eligible for inlining. Generally inlining
     // other functions is incorrect because they could reference symbols that aren't exported.
     let is_generic = callsite.callee.args.non_erasable_generics().next().is_some();
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index f4ac5c6aa80..2864cc0b9fe 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -444,7 +444,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             | Rvalue::Cast(..)
             | Rvalue::ShallowInitBox(..)
             | Rvalue::Discriminant(..)
-            | Rvalue::NullaryOp(..) => {}
+            | Rvalue::NullaryOp(..)
+            | Rvalue::WrapUnsafeBinder(..) => {}
         }
 
         // FIXME we need to revisit this for #67176
@@ -546,7 +547,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         let val: Value<'_> = match *rvalue {
             ThreadLocalRef(_) => return None,
 
-            Use(ref operand) => self.eval_operand(operand)?.into(),
+            Use(ref operand) | WrapUnsafeBinder(ref operand, _) => {
+                self.eval_operand(operand)?.into()
+            }
 
             CopyForDeref(place) => self.eval_place(place)?.into(),
 
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 2dc55e3614e..b572f6ca0b3 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -33,6 +33,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_middle::util::Providers;
 use rustc_middle::{bug, query, span_bug};
+use rustc_mir_build::builder::build_mir;
 use rustc_span::source_map::Spanned;
 use rustc_span::{DUMMY_SP, sym};
 use tracing::debug;
@@ -44,6 +45,7 @@ use std::sync::LazyLock;
 
 use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel};
 
+mod check_pointers;
 mod cost_checker;
 mod cross_crate_inline;
 mod deduce_param_attrs;
@@ -118,6 +120,7 @@ declare_passes! {
     mod check_call_recursion : CheckCallRecursion, CheckDropRecursion;
     mod check_alignment : CheckAlignment;
     mod check_const_item_mutation : CheckConstItemMutation;
+    mod check_null : CheckNull;
     mod check_packed_ref : CheckPackedRef;
     mod check_undefined_transmutes : CheckUndefinedTransmutes;
     // This pass is public to allow external drivers to perform MIR cleanup
@@ -368,7 +371,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
 }
 
 fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
-    let mut body = tcx.build_mir(def);
+    let mut body = build_mir(tcx, def);
 
     pass_manager::dump_mir_for_phase_change(tcx, &body);
 
@@ -418,11 +421,11 @@ fn mir_promoted(
     };
 
     // the `has_ffi_unwind_calls` query uses the raw mir, so make sure it is run.
-    tcx.ensure_with_value().has_ffi_unwind_calls(def);
+    tcx.ensure_done().has_ffi_unwind_calls(def);
 
     // the `by_move_body` query uses the raw mir, so make sure it is run.
     if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) {
-        tcx.ensure_with_value().coroutine_by_move_body_def_id(def);
+        tcx.ensure_done().coroutine_by_move_body_def_id(def);
     }
 
     let mut body = tcx.mir_built(def).steal();
@@ -485,7 +488,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
 /// end up missing the source MIR due to stealing happening.
 fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
     if tcx.is_coroutine(def.to_def_id()) {
-        tcx.ensure_with_value().mir_coroutine_witnesses(def);
+        tcx.ensure_done().mir_coroutine_witnesses(def);
     }
 
     // We only need to borrowck non-synthetic MIR.
@@ -498,7 +501,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
         if pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
             || inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id())
         {
-            tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
+            tcx.ensure_done().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
         }
     }
 
@@ -642,6 +645,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &[
             // Add some UB checks before any UB gets optimized away.
             &check_alignment::CheckAlignment,
+            &check_null::CheckNull,
             // Before inlining: trim down MIR with passes to reduce inlining work.
 
             // Has to be done before inlining, otherwise actual call will be almost always inlined.
@@ -729,7 +733,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
         // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked`
         // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it
         // computes and caches its result.
-        Some(hir::ConstContext::ConstFn) => tcx.ensure_with_value().mir_for_ctfe(did),
+        Some(hir::ConstContext::ConstFn) => tcx.ensure_done().mir_for_ctfe(did),
         None => {}
         Some(other) => panic!("do not use `optimized_mir` for constants: {other:?}"),
     }
@@ -768,7 +772,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec<Promoted, Body<'_
     }
 
     if !tcx.is_synthetic_mir(def) {
-        tcx.ensure_with_value().mir_borrowck(def);
+        tcx.ensure_done().mir_borrowck(def);
     }
     let mut promoted = tcx.mir_promoted(def).1.steal();
 
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 6aa3343bb6e..9101c9bfc9a 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -293,7 +293,8 @@ impl<'tcx> Validator<'_, 'tcx> {
             // Recurse directly.
             ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Subtype(_)
-            | ProjectionElem::Subslice { .. } => {}
+            | ProjectionElem::Subslice { .. }
+            | ProjectionElem::UnwrapUnsafeBinder(_) => {}
 
             // Never recurse.
             ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
@@ -426,7 +427,9 @@ impl<'tcx> Validator<'_, 'tcx> {
 
     fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
         match rvalue {
-            Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
+            Rvalue::Use(operand)
+            | Rvalue::Repeat(operand, _)
+            | Rvalue::WrapUnsafeBinder(operand, _) => {
                 self.validate_operand(operand)?;
             }
             Rvalue::CopyForDeref(place) => {
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 5881264cba5..e282eaf761c 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -807,6 +807,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     )
                 }
             }
+            ProjectionElem::UnwrapUnsafeBinder(unwrapped_ty) => {
+                let binder_ty = place_ref.ty(&self.body.local_decls, self.tcx);
+                let ty::UnsafeBinder(binder_ty) = *binder_ty.ty.kind() else {
+                    self.fail(
+                        location,
+                        format!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"),
+                    );
+                    return;
+                };
+                let binder_inner_ty = self.tcx.instantiate_bound_regions_with_erased(*binder_ty);
+                if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) {
+                    self.fail(
+                        location,
+                        format!(
+                            "Cannot unwrap unsafe binder {binder_ty:?} into type {unwrapped_ty:?}"
+                        ),
+                    );
+                }
+            }
             _ => {}
         }
         self.super_projection_elem(place_ref, elem, context, location);
@@ -1362,6 +1381,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             | Rvalue::RawPtr(_, _)
             | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
             | Rvalue::Discriminant(_) => {}
+
+            Rvalue::WrapUnsafeBinder(op, ty) => {
+                let unwrapped_ty = op.ty(self.body, self.tcx);
+                let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
+                    self.fail(
+                        location,
+                        format!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"),
+                    );
+                    return;
+                };
+                let binder_inner_ty = self.tcx.instantiate_bound_regions_with_erased(*binder_ty);
+                if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) {
+                    self.fail(
+                        location,
+                        format!("Cannot wrap {unwrapped_ty:?} into unsafe binder {binder_ty:?}"),
+                    );
+                }
+            }
         }
         self.super_rvalue(rvalue, location);
     }
diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml
index 9bdaeb015cd..5462105e5e8 100644
--- a/compiler/rustc_monomorphize/Cargo.toml
+++ b/compiler/rustc_monomorphize/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 rustc_abi = { path = "../rustc_abi" }
+rustc_ast = { path = "../rustc_ast" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
@@ -15,6 +16,7 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
+rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_target = { path = "../rustc_target" }
 serde = "1"
 serde_json = "1"
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index bb603df1129..ae31ed59391 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -257,7 +257,7 @@ struct SharedState<'tcx> {
 
 pub(crate) struct UsageMap<'tcx> {
     // Maps every mono item to the mono items used by it.
-    used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
+    pub used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
 
     // Maps every mono item to the mono items that use it.
     user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
@@ -814,6 +814,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 mir::AssertKind::MisalignedPointerDereference { .. } => {
                     push_mono_lang_item(self, LangItem::PanicMisalignedPointerDereference);
                 }
+                mir::AssertKind::NullPointerDereference => {
+                    push_mono_lang_item(self, LangItem::PanicNullPointerDereference);
+                }
                 _ => {
                     push_mono_lang_item(self, msg.panic_function());
                 }
@@ -950,7 +953,7 @@ fn visit_instance_use<'tcx>(
 
 /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
 /// can just link to the upstream crate and therefore don't need a mono item.
-fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -> bool {
+fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
     let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
         return true;
     };
@@ -973,7 +976,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
         return true;
     }
 
-    if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(*tcx).is_some() {
+    if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(tcx).is_some() {
         // We can link to the item in question, no instance needed in this crate.
         return false;
     }
@@ -1138,11 +1141,12 @@ fn create_mono_items_for_vtable_methods<'tcx>(
         bug!("create_mono_items_for_vtable_methods: {trait_ty:?} not a trait type");
     };
     if let Some(principal) = trait_ty.principal() {
-        let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
-        assert!(!poly_trait_ref.has_escaping_bound_vars());
+        let trait_ref =
+            tcx.instantiate_bound_regions_with_erased(principal.with_self_ty(tcx, impl_ty));
+        assert!(!trait_ref.has_escaping_bound_vars());
 
         // Walk all methods of the trait, including those of its supertraits
-        let entries = tcx.vtable_entries(poly_trait_ref);
+        let entries = tcx.vtable_entries(trait_ref);
         debug!(?entries);
         let methods = entries
             .iter()
@@ -1197,7 +1201,12 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
             }
         }
         GlobalAlloc::VTable(ty, dyn_ty) => {
-            let alloc_id = tcx.vtable_allocation((ty, dyn_ty.principal()));
+            let alloc_id = tcx.vtable_allocation((
+                ty,
+                dyn_ty
+                    .principal()
+                    .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
+            ));
             collect_alloc(tcx, alloc_id, output)
         }
     }
@@ -1213,7 +1222,7 @@ fn collect_items_of_instance<'tcx>(
     mode: CollectionMode,
 ) -> (MonoItems<'tcx>, MonoItems<'tcx>) {
     // This item is getting monomorphized, do mono-time checks.
-    tcx.ensure().check_mono_item(instance);
+    tcx.ensure_ok().check_mono_item(instance);
 
     let body = tcx.instance_mir(instance.def);
     // Naively, in "used" collection mode, all functions get added to *both* `used_items` and
@@ -1454,11 +1463,14 @@ impl<'v> RootCollector<'_, 'v> {
                 self.output.push(dummy_spanned(MonoItem::Static(def_id)));
             }
             DefKind::Const => {
-                // const items only generate mono items if they are
-                // actually used somewhere. Just declaring them is insufficient.
+                // Const items only generate mono items if they are actually used somewhere.
+                // Just declaring them is insufficient.
 
-                // but even just declaring them must collect the items they refer to
-                if let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) {
+                // But even just declaring them must collect the items they refer to
+                // unless their generics require monomorphization.
+                if !self.tcx.generics_of(id.owner_id).requires_monomorphization(self.tcx)
+                    && let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id())
+                {
                     collect_const_value(self.tcx, val, self.output);
                 }
             }
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index e08c348a64d..3ef061195da 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -92,6 +92,8 @@
 //! source-level module, functions from the same module will be available for
 //! inlining, even when they are not marked `#[inline]`.
 
+mod autodiff;
+
 use std::cmp;
 use std::collections::hash_map::Entry;
 use std::fs::{self, File};
@@ -251,7 +253,17 @@ where
             can_export_generics,
             always_export_generics,
         );
-        if visibility == Visibility::Hidden && can_be_internalized {
+
+        // We can't differentiate something that got inlined.
+        let autodiff_active = cfg!(llvm_enzyme)
+            && cx
+                .tcx
+                .codegen_fn_attrs(mono_item.def_id())
+                .autodiff_item
+                .as_ref()
+                .is_some_and(|ad| ad.is_active());
+
+        if !autodiff_active && visibility == Visibility::Hidden && can_be_internalized {
             internalization_candidates.insert(mono_item);
         }
         let size_estimate = mono_item.size_estimate(cx.tcx);
@@ -1167,15 +1179,27 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio
         }
     }
 
+    #[cfg(not(llvm_enzyme))]
+    let autodiff_mono_items: Vec<_> = vec![];
+    #[cfg(llvm_enzyme)]
+    let mut autodiff_mono_items: Vec<_> = vec![];
     let mono_items: DefIdSet = items
         .iter()
         .filter_map(|mono_item| match *mono_item {
-            MonoItem::Fn(ref instance) => Some(instance.def_id()),
+            MonoItem::Fn(ref instance) => {
+                #[cfg(llvm_enzyme)]
+                autodiff_mono_items.push((mono_item, instance));
+                Some(instance.def_id())
+            }
             MonoItem::Static(def_id) => Some(def_id),
             _ => None,
         })
         .collect();
 
+    let autodiff_items =
+        autodiff::find_autodiff_source_functions(tcx, &usage_map, autodiff_mono_items);
+    let autodiff_items = tcx.arena.alloc_from_iter(autodiff_items);
+
     // Output monomorphization stats per def_id
     if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
         if let Err(err) =
@@ -1236,7 +1260,11 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio
         }
     }
 
-    MonoItemPartitions { all_mono_items: tcx.arena.alloc(mono_items), codegen_units }
+    MonoItemPartitions {
+        all_mono_items: tcx.arena.alloc(mono_items),
+        codegen_units,
+        autodiff_items,
+    }
 }
 
 /// Outputs stats about instantiation counts and estimated size, per `MonoItem`'s
diff --git a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs
new file mode 100644
index 00000000000..bce31bf0748
--- /dev/null
+++ b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs
@@ -0,0 +1,121 @@
+use rustc_ast::expand::autodiff_attrs::{AutoDiffItem, DiffActivity};
+use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_middle::bug;
+use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_symbol_mangling::symbol_name_for_instance_in_crate;
+use tracing::{debug, trace};
+
+use crate::partitioning::UsageMap;
+
+fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec<DiffActivity>) {
+    if !matches!(fn_ty.kind(), ty::FnDef(..)) {
+        bug!("expected fn def for autodiff, got {:?}", fn_ty);
+    }
+    let fnc_binder: ty::Binder<'_, ty::FnSig<'_>> = fn_ty.fn_sig(tcx);
+
+    // If rustc compiles the unmodified primal, we know that this copy of the function
+    // also has correct lifetimes. We know that Enzyme won't free the shadow too early
+    // (or actually at all), so let's strip lifetimes when computing the layout.
+    let x = tcx.instantiate_bound_regions_with_erased(fnc_binder);
+    let mut new_activities = vec![];
+    let mut new_positions = vec![];
+    for (i, ty) in x.inputs().iter().enumerate() {
+        if let Some(inner_ty) = ty.builtin_deref(true) {
+            if ty.is_fn_ptr() {
+                // FIXME(ZuseZ4): add a nicer error, or just figure out how to support them,
+                // since Enzyme itself can handle them.
+                tcx.dcx().err("function pointers are currently not supported in autodiff");
+            }
+            if inner_ty.is_slice() {
+                // We know that the length will be passed as extra arg.
+                if !da.is_empty() {
+                    // We are looking at a slice. The length of that slice will become an
+                    // extra integer on llvm level. Integers are always const.
+                    // However, if the slice get's duplicated, we want to know to later check the
+                    // size. So we mark the new size argument as FakeActivitySize.
+                    let activity = match da[i] {
+                        DiffActivity::DualOnly
+                        | DiffActivity::Dual
+                        | DiffActivity::DuplicatedOnly
+                        | DiffActivity::Duplicated => DiffActivity::FakeActivitySize,
+                        DiffActivity::Const => DiffActivity::Const,
+                        _ => bug!("unexpected activity for ptr/ref"),
+                    };
+                    new_activities.push(activity);
+                    new_positions.push(i + 1);
+                }
+                continue;
+            }
+        }
+    }
+    // now add the extra activities coming from slices
+    // Reverse order to not invalidate the indices
+    for _ in 0..new_activities.len() {
+        let pos = new_positions.pop().unwrap();
+        let activity = new_activities.pop().unwrap();
+        da.insert(pos, activity);
+    }
+}
+
+pub(crate) fn find_autodiff_source_functions<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    usage_map: &UsageMap<'tcx>,
+    autodiff_mono_items: Vec<(&MonoItem<'tcx>, &Instance<'tcx>)>,
+) -> Vec<AutoDiffItem> {
+    let mut autodiff_items: Vec<AutoDiffItem> = vec![];
+    for (item, instance) in autodiff_mono_items {
+        let target_id = instance.def_id();
+        let cg_fn_attr = tcx.codegen_fn_attrs(target_id).autodiff_item.clone();
+        let Some(target_attrs) = cg_fn_attr else {
+            continue;
+        };
+        let mut input_activities: Vec<DiffActivity> = target_attrs.input_activity.clone();
+        if target_attrs.is_source() {
+            trace!("source found: {:?}", target_id);
+        }
+        if !target_attrs.apply_autodiff() {
+            continue;
+        }
+
+        let target_symbol = symbol_name_for_instance_in_crate(tcx, instance.clone(), LOCAL_CRATE);
+
+        let source =
+            usage_map.used_map.get(&item).unwrap().into_iter().find_map(|item| match *item {
+                MonoItem::Fn(ref instance_s) => {
+                    let source_id = instance_s.def_id();
+                    if let Some(ad) = &tcx.codegen_fn_attrs(source_id).autodiff_item
+                        && ad.is_active()
+                    {
+                        return Some(instance_s);
+                    }
+                    None
+                }
+                _ => None,
+            });
+        let inst = match source {
+            Some(source) => source,
+            None => continue,
+        };
+
+        debug!("source_id: {:?}", inst.def_id());
+        let fn_ty = inst.ty(tcx, ty::TypingEnv::fully_monomorphized());
+        assert!(fn_ty.is_fn());
+        adjust_activity_to_abi(tcx, fn_ty, &mut input_activities);
+        let symb = symbol_name_for_instance_in_crate(tcx, inst.clone(), LOCAL_CRATE);
+
+        let mut new_target_attrs = target_attrs.clone();
+        new_target_attrs.input_activity = input_activities;
+        let itm = new_target_attrs.into_item(symb, target_symbol);
+        autodiff_items.push(itm);
+    }
+
+    if !autodiff_items.is_empty() {
+        trace!("AUTODIFF ITEMS EXIST");
+        for item in &mut *autodiff_items {
+            trace!("{}", &item);
+        }
+    }
+
+    autodiff_items
+}
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 62a7c84bc28..7eeed721d5a 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -522,7 +522,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
             // FIXME: See comment above -- we could fold the region separately or something.
             ty::ConstKind::Bound(_, _)
             | ty::ConstKind::Unevaluated(_)
-            | ty::ConstKind::Value(_, _)
+            | ty::ConstKind::Value(_)
             | ty::ConstKind::Error(_)
             | ty::ConstKind::Expr(_) => return c.super_fold_with(self),
         };
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 8d1194ee539..1fa35b60304 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -160,9 +160,7 @@ where
             ty::ConstKind::Infer(_) => {
                 self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
             }
-            ty::ConstKind::Placeholder(_)
-            | ty::ConstKind::Value(_, _)
-            | ty::ConstKind::Error(_) => {
+            ty::ConstKind::Placeholder(_) | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) => {
                 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             }
             // We can freely ICE here as:
@@ -199,7 +197,7 @@ where
                 unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`")
             }
             ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct),
-            ty::ConstKind::Value(ty, _) => ty,
+            ty::ConstKind::Value(cv) => cv.ty(),
             ty::ConstKind::Placeholder(placeholder) => {
                 self.cx().find_const_ty_from_env(goal.param_env, placeholder)
             }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index a5b73ce4098..ffd46f20767 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -3114,9 +3114,8 @@ impl<'a> Parser<'a> {
             let span_before_body = this.prev_token.span;
             let arm_body;
             let is_fat_arrow = this.check(exp!(FatArrow));
-            let is_almost_fat_arrow = TokenKind::FatArrow
-                .similar_tokens()
-                .is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind));
+            let is_almost_fat_arrow =
+                TokenKind::FatArrow.similar_tokens().contains(&this.token.kind);
 
             // this avoids the compiler saying that a `,` or `}` was expected even though
             // the pattern isn't a never pattern (and thus an arm body is required)
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 714a60cb179..faebb5a40bb 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -924,10 +924,8 @@ impl<'a> Parser<'a> {
 
                                 _ => {
                                     // Attempt to keep parsing if it was a similar separator.
-                                    if let Some(tokens) = exp.tok.similar_tokens() {
-                                        if tokens.contains(&self.token.kind) {
-                                            self.bump();
-                                        }
+                                    if exp.tok.similar_tokens().contains(&self.token.kind) {
+                                        self.bump();
                                     }
                                 }
                             }
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 09c88e7f83b..d021ea107ed 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -363,12 +363,7 @@ impl<'a> Parser<'a> {
     /// Notifies of an error. The message doesn't actually need to be of type
     /// String, but I think it does when this eventually uses conditions so it
     /// might as well start using it now.
-    fn err<S1: Into<String>, S2: Into<String>>(
-        &mut self,
-        description: S1,
-        label: S2,
-        span: InnerSpan,
-    ) {
+    fn err(&mut self, description: impl Into<String>, label: impl Into<String>, span: InnerSpan) {
         self.errors.push(ParseError {
             description: description.into(),
             note: None,
@@ -382,11 +377,11 @@ impl<'a> Parser<'a> {
     /// Notifies of an error. The message doesn't actually need to be of type
     /// String, but I think it does when this eventually uses conditions so it
     /// might as well start using it now.
-    fn err_with_note<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
+    fn err_with_note(
         &mut self,
-        description: S1,
-        label: S2,
-        note: S3,
+        description: impl Into<String>,
+        label: impl Into<String>,
+        note: impl Into<String>,
         span: InnerSpan,
     ) {
         self.errors.push(ParseError {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index e19819a22b4..837da6e7724 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -2471,6 +2471,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 }))),
                 terr,
                 false,
+                None,
             );
             diag.emit();
             self.abort.set(true);
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index e5b63b9b4a6..95f18eaa7ef 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -10,11 +10,10 @@ use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
 use rustc_abi::FieldIdx;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::MultiSpan;
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Node, PatKind, TyKind};
+use rustc_hir::{self as hir, Node, PatKind, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::privacy::Level;
 use rustc_middle::query::Providers;
@@ -637,10 +636,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
                 let res = self.typeck_results().qpath_res(path, pat.hir_id);
                 self.handle_field_pattern_match(pat, res, fields);
             }
-            PatKind::Path(ref qpath) => {
-                let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
-                self.handle_res(res);
-            }
             PatKind::TupleStruct(ref qpath, fields, dotdot) => {
                 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
                 self.handle_tuple_field_pattern_match(pat, res, fields, dotdot);
@@ -652,6 +647,17 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
         self.in_pat = false;
     }
 
+    fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) {
+        match &expr.kind {
+            rustc_hir::PatExprKind::Path(qpath) => {
+                let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
+                self.handle_res(res);
+            }
+            _ => {}
+        }
+        intravisit::walk_pat_expr(self, expr);
+    }
+
     fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
         self.handle_res(path.res);
         intravisit::walk_path(self, path);
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 8b10543f6fd..6d9c70177a4 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -5,10 +5,10 @@
 use rustc_ast::visit::BoundKind;
 use rustc_ast::{self as ast, NodeId, visit as ast_visit};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::thousands::format_with_underscores;
 use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::TyCtxt;
-use rustc_middle::util::common::to_readable_str;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
 
@@ -144,10 +144,10 @@ impl<'k> StatCollector<'k> {
                 "{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}",
                 prefix,
                 label,
-                to_readable_str(size),
+                format_with_underscores(size),
                 percent(size, total_size),
-                to_readable_str(node.stats.count),
-                to_readable_str(node.stats.size)
+                format_with_underscores(node.stats.count),
+                format_with_underscores(node.stats.size)
             );
             if !node.subnodes.is_empty() {
                 // We will soon sort, so the initial order does not matter.
@@ -163,9 +163,9 @@ impl<'k> StatCollector<'k> {
                         "{} - {:<18}{:>10} ({:4.1}%){:>14}",
                         prefix,
                         label,
-                        to_readable_str(size),
+                        format_with_underscores(size),
                         percent(size, total_size),
-                        to_readable_str(subnode.count),
+                        format_with_underscores(subnode.count),
                     );
                 }
             }
@@ -175,8 +175,8 @@ impl<'k> StatCollector<'k> {
             "{} {:<18}{:>10}        {:>14}",
             prefix,
             "Total",
-            to_readable_str(total_size),
-            to_readable_str(total_count),
+            format_with_underscores(total_size),
+            format_with_underscores(total_count),
         );
         eprintln!("{prefix}");
     }
@@ -298,7 +298,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
             TupleStruct,
             Or,
             Never,
-            Path,
             Tuple,
             Box,
             Deref,
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 73da8855e10..60f7616a5fb 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -1522,6 +1522,14 @@ impl<'tcx> Liveness<'_, 'tcx> {
     }
 
     fn warn_about_unused_args(&self, body: &hir::Body<'_>, entry_ln: LiveNode) {
+        if let Some(intrinsic) =
+            self.ir.tcx.intrinsic(self.ir.tcx.hir().body_owner_def_id(body.id()))
+        {
+            if intrinsic.must_be_overridden {
+                return;
+            }
+        }
+
         for p in body.params {
             self.check_unused_vars_in_pat(
                 p.pat,
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index a52f080038d..34f1ca55c78 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -5,8 +5,8 @@ use std::mem::replace;
 use std::num::NonZero;
 
 use rustc_attr_parsing::{
-    self as attr, AllowedThroughUnstableModules, ConstStability, DeprecatedSince, Stability,
-    StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER,
+    self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince,
+    UnstableReason, VERSION_PLACEHOLDER,
 };
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
@@ -880,7 +880,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
 
             if item_is_allowed {
                 // The item itself is allowed; check whether the path there is also allowed.
-                let is_allowed_through_unstable_modules: Option<AllowedThroughUnstableModules> =
+                let is_allowed_through_unstable_modules: Option<Symbol> =
                     self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level {
                         StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
                             allowed_through_unstable_modules
@@ -888,83 +888,79 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                         _ => None,
                     });
 
-                if is_allowed_through_unstable_modules.is_none() {
-                    // Check parent modules stability as well if the item the path refers to is itself
-                    // stable. We only emit warnings for unstable path segments if the item is stable
-                    // or allowed because stability is often inherited, so the most common case is that
-                    // both the segments and the item are unstable behind the same feature flag.
-                    //
-                    // We check here rather than in `visit_path_segment` to prevent visiting the last
-                    // path segment twice
-                    //
-                    // We include special cases via #[rustc_allowed_through_unstable_modules] for items
-                    // that were accidentally stabilized through unstable paths before this check was
-                    // added, such as `core::intrinsics::transmute`
-                    let parents = path.segments.iter().rev().skip(1);
-                    for path_segment in parents {
-                        if let Some(def_id) = path_segment.res.opt_def_id() {
-                            // use `None` for id to prevent deprecation check
-                            self.tcx.check_stability_allow_unstable(
-                                def_id,
-                                None,
-                                path.span,
-                                None,
-                                if is_unstable_reexport(self.tcx, id) {
-                                    AllowUnstable::Yes
-                                } else {
-                                    AllowUnstable::No
-                                },
-                            );
-                        }
-                    }
-                } else if let Some(AllowedThroughUnstableModules::WithDeprecation(deprecation)) =
-                    is_allowed_through_unstable_modules
-                {
-                    // Similar to above, but we cannot use `check_stability_allow_unstable` as that would
-                    // immediately show the stability error. We just want to know the result and disaplay
-                    // our own kind of error.
-                    let parents = path.segments.iter().rev().skip(1);
-                    for path_segment in parents {
-                        if let Some(def_id) = path_segment.res.opt_def_id() {
-                            // use `None` for id to prevent deprecation check
-                            let eval_result = self.tcx.eval_stability_allow_unstable(
-                                def_id,
-                                None,
-                                path.span,
-                                None,
-                                if is_unstable_reexport(self.tcx, id) {
-                                    AllowUnstable::Yes
-                                } else {
-                                    AllowUnstable::No
-                                },
-                            );
-                            let is_allowed = matches!(eval_result, EvalResult::Allow);
-                            if !is_allowed {
-                                // Calculating message for lint involves calling `self.def_path_str`,
-                                // which will by default invoke the expensive `visible_parent_map` query.
-                                // Skip all that work if the lint is allowed anyway.
-                                if self.tcx.lint_level_at_node(DEPRECATED, id).0
-                                    == lint::Level::Allow
-                                {
-                                    return;
-                                }
-                                // Show a deprecation message.
-                                let def_path =
-                                    with_no_trimmed_paths!(self.tcx.def_path_str(def_id));
-                                let def_kind = self.tcx.def_descr(def_id);
-                                let diag = Deprecated {
-                                    sub: None,
-                                    kind: def_kind.to_owned(),
-                                    path: def_path,
-                                    note: Some(deprecation),
-                                    since_kind: lint::DeprecatedSinceKind::InEffect,
-                                };
-                                self.tcx.emit_node_span_lint(
-                                    DEPRECATED,
-                                    id,
-                                    method_span.unwrap_or(path.span),
-                                    diag,
+                // Check parent modules stability as well if the item the path refers to is itself
+                // stable. We only emit errors for unstable path segments if the item is stable
+                // or allowed because stability is often inherited, so the most common case is that
+                // both the segments and the item are unstable behind the same feature flag.
+                //
+                // We check here rather than in `visit_path_segment` to prevent visiting the last
+                // path segment twice
+                //
+                // We include special cases via #[rustc_allowed_through_unstable_modules] for items
+                // that were accidentally stabilized through unstable paths before this check was
+                // added, such as `core::intrinsics::transmute`
+                let parents = path.segments.iter().rev().skip(1);
+                for path_segment in parents {
+                    if let Some(def_id) = path_segment.res.opt_def_id() {
+                        match is_allowed_through_unstable_modules {
+                            None => {
+                                // Emit a hard stability error if this path is not stable.
+
+                                // use `None` for id to prevent deprecation check
+                                self.tcx.check_stability_allow_unstable(
+                                    def_id,
+                                    None,
+                                    path.span,
+                                    None,
+                                    if is_unstable_reexport(self.tcx, id) {
+                                        AllowUnstable::Yes
+                                    } else {
+                                        AllowUnstable::No
+                                    },
+                                );
+                            }
+                            Some(deprecation) => {
+                                // Call the stability check directly so that we can control which
+                                // diagnostic is emitted.
+                                let eval_result = self.tcx.eval_stability_allow_unstable(
+                                    def_id,
+                                    None,
+                                    path.span,
+                                    None,
+                                    if is_unstable_reexport(self.tcx, id) {
+                                        AllowUnstable::Yes
+                                    } else {
+                                        AllowUnstable::No
+                                    },
                                 );
+                                let is_allowed = matches!(eval_result, EvalResult::Allow);
+                                if !is_allowed {
+                                    // Calculating message for lint involves calling `self.def_path_str`,
+                                    // which will by default invoke the expensive `visible_parent_map` query.
+                                    // Skip all that work if the lint is allowed anyway.
+                                    if self.tcx.lint_level_at_node(DEPRECATED, id).0
+                                        == lint::Level::Allow
+                                    {
+                                        return;
+                                    }
+                                    // Show a deprecation message.
+                                    let def_path =
+                                        with_no_trimmed_paths!(self.tcx.def_path_str(def_id));
+                                    let def_kind = self.tcx.def_descr(def_id);
+                                    let diag = Deprecated {
+                                        sub: None,
+                                        kind: def_kind.to_owned(),
+                                        path: def_path,
+                                        note: Some(deprecation),
+                                        since_kind: lint::DeprecatedSinceKind::InEffect,
+                                    };
+                                    self.tcx.emit_node_span_lint(
+                                        DEPRECATED,
+                                        id,
+                                        method_span.unwrap_or(path.span),
+                                        diag,
+                                    );
+                                }
                             }
                         }
                     }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index d19df08519d..3842b7035e5 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -24,7 +24,7 @@ use rustc_ast::MacroDef;
 use rustc_ast::visit::{VisitorResult, try_visit};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
-use rustc_errors::MultiSpan;
+use rustc_errors::{MultiSpan, listify};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::{self, InferKind, Visitor};
@@ -958,29 +958,15 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         //    |         ^^ field `gamma` is private  # `fields.2` is `false`
 
         // Get the list of all private fields for the main message.
-        let field_names: Vec<_> = fields.iter().map(|(name, _, _)| name).collect();
-        let field_names = match &field_names[..] {
-            [] => return,
-            [name] => format!("`{name}`"),
-            [fields @ .., last] => format!(
-                "{} and `{last}`",
-                fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
-            ),
-        };
+        let Some(field_names) = listify(&fields[..], |(n, _, _)| format!("`{n}`")) else { return };
         let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
 
         // Get the list of all private fields when pointing at the `..rest`.
         let rest_field_names: Vec<_> =
             fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
         let rest_len = rest_field_names.len();
-        let rest_field_names = match &rest_field_names[..] {
-            [] => String::new(),
-            [name] => format!("`{name}`"),
-            [fields @ .., last] => format!(
-                "{} and `{last}`",
-                fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
-            ),
-        };
+        let rest_field_names =
+            listify(&rest_field_names[..], |n| format!("`{n}`")).unwrap_or_default();
         // Get all the labels for each field or `..rest` in the primary MultiSpan.
         let labels = fields
             .iter()
@@ -1005,7 +991,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
             } else {
                 None
             },
-            field_names: field_names.clone(),
+            field_names,
             variant_descr: def.variant_descr(),
             def_path_str: self.tcx.def_path_str(def.did()),
             labels,
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index d2bb0b3f277..bbc83cca99d 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -224,7 +224,6 @@ pub fn query_system<'a>(
 rustc_middle::rustc_query_append! { define_queries! }
 
 pub fn provide(providers: &mut rustc_middle::util::Providers) {
-    providers.hooks.alloc_self_profile_query_strings =
-        |tcx| alloc_self_profile_query_strings(tcx.tcx);
-    providers.hooks.query_key_hash_verify_all = |tcx| query_key_hash_verify_all(tcx.tcx);
+    providers.hooks.alloc_self_profile_query_strings = alloc_self_profile_query_strings;
+    providers.hooks.query_key_hash_verify_all = query_key_hash_verify_all;
 }
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index 09648e28df4..5f0c1afdf64 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -103,7 +103,7 @@ fn encode_args<'tcx>(
 /// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
 fn encode_const<'tcx>(
     tcx: TyCtxt<'tcx>,
-    c: Const<'tcx>,
+    ct: Const<'tcx>,
     ct_ty: Ty<'tcx>,
     dict: &mut FxHashMap<DictKey<'tcx>, usize>,
     options: EncodeTyOptions,
@@ -111,7 +111,7 @@ fn encode_const<'tcx>(
     // L<element-type>[n][<element-value>]E as literal argument
     let mut s = String::from('L');
 
-    match c.kind() {
+    match ct.kind() {
         // Const parameters
         ty::ConstKind::Param(..) => {
             // L<element-type>E as literal argument
@@ -121,18 +121,18 @@ fn encode_const<'tcx>(
         }
 
         // Literal arguments
-        ty::ConstKind::Value(ct_ty, ..) => {
+        ty::ConstKind::Value(cv) => {
             // L<element-type>[n]<element-value>E as literal argument
 
             // Element type
-            s.push_str(&encode_ty(tcx, ct_ty, dict, options));
+            s.push_str(&encode_ty(tcx, cv.ty, dict, options));
 
             // The only allowed types of const values are bool, u8, u16, u32,
             // u64, u128, usize i8, i16, i32, i64, i128, isize, and char. The
             // bool value false is encoded as 0 and true as 1.
-            match ct_ty.kind() {
+            match cv.ty.kind() {
                 ty::Int(ity) => {
-                    let bits = c
+                    let bits = cv
                         .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
                         .expect("expected monomorphic const in cfi");
                     let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
@@ -142,30 +142,30 @@ fn encode_const<'tcx>(
                     let _ = write!(s, "{val}");
                 }
                 ty::Uint(_) => {
-                    let val = c
+                    let val = cv
                         .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized())
                         .expect("expected monomorphic const in cfi");
                     let _ = write!(s, "{val}");
                 }
                 ty::Bool => {
-                    let val = c.try_to_bool().expect("expected monomorphic const in cfi");
+                    let val = cv.try_to_bool().expect("expected monomorphic const in cfi");
                     let _ = write!(s, "{val}");
                 }
                 _ => {
-                    bug!("encode_const: unexpected type `{:?}`", ct_ty);
+                    bug!("encode_const: unexpected type `{:?}`", cv.ty);
                 }
             }
         }
 
         _ => {
-            bug!("encode_const: unexpected kind `{:?}`", c.kind());
+            bug!("encode_const: unexpected kind `{:?}`", ct.kind());
         }
     }
 
     // Close the "L..E" pair
     s.push('E');
 
-    compress(dict, DictKey::Const(c), &mut s);
+    compress(dict, DictKey::Const(ct), &mut s);
 
     s
 }
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 9c6186d6882..b711c238d59 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -51,8 +51,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
     // Transforms a ty:Ty for being encoded and used in the substitution dictionary.
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         match t.kind() {
-            ty::Array(..)
-            | ty::Closure(..)
+            ty::Closure(..)
             | ty::Coroutine(..)
             | ty::CoroutineClosure(..)
             | ty::CoroutineWitness(..)
@@ -67,6 +66,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
             | ty::Tuple(..)
             | ty::UnsafeBinder(_) => t.super_fold_with(self),
 
+            // Don't transform the type of the array length and keep it as `usize`.
+            // This is required for `try_to_target_usize` to work correctly.
+            &ty::Array(inner, len) => {
+                let inner = self.fold_ty(inner);
+                Ty::new_array_with_const_len(self.tcx, inner, len)
+            }
+
             ty::Bool => {
                 if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
                     // Note: on all platforms that Rust's currently supports, its size and alignment
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index f3c21992784..b4597ae2515 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -1,10 +1,9 @@
 use std::cmp;
 
 use rustc_abi::{Align, Size};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lock;
 use rustc_span::Symbol;
-use rustc_span::def_id::DefId;
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub struct VariantInfo {
@@ -71,29 +70,9 @@ pub struct TypeSizeInfo {
     pub variants: Vec<VariantInfo>,
 }
 
-pub struct VTableSizeInfo {
-    pub trait_name: String,
-
-    /// Number of entries in a vtable with the current algorithm
-    /// (i.e. with upcasting).
-    pub entries: usize,
-
-    /// Number of entries in a vtable, as-if we did not have trait upcasting.
-    pub entries_ignoring_upcasting: usize,
-
-    /// Number of entries in a vtable needed solely for upcasting
-    /// (i.e. `entries - entries_ignoring_upcasting`).
-    pub entries_for_upcasting: usize,
-
-    /// Cost of having upcasting in % relative to the number of entries without
-    /// upcasting (i.e. `entries_for_upcasting / entries_ignoring_upcasting * 100%`).
-    pub upcasting_cost_percent: f64,
-}
-
 #[derive(Default)]
 pub struct CodeStats {
     type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
-    vtable_sizes: Lock<FxHashMap<DefId, VTableSizeInfo>>,
 }
 
 impl CodeStats {
@@ -127,14 +106,6 @@ impl CodeStats {
         self.type_sizes.borrow_mut().insert(info);
     }
 
-    pub fn record_vtable_size(&self, trait_did: DefId, trait_name: &str, info: VTableSizeInfo) {
-        let prev = self.vtable_sizes.lock().insert(trait_did, info);
-        assert!(
-            prev.is_none(),
-            "size of vtable for `{trait_name}` ({trait_did:?}) is already recorded"
-        );
-    }
-
     pub fn print_type_sizes(&self) {
         let type_sizes = self.type_sizes.borrow();
         // We will soon sort, so the initial order does not matter.
@@ -238,33 +209,4 @@ impl CodeStats {
             }
         }
     }
-
-    pub fn print_vtable_sizes(&self, crate_name: Symbol) {
-        // We will soon sort, so the initial order does not matter.
-        #[allow(rustc::potential_query_instability)]
-        let mut infos =
-            std::mem::take(&mut *self.vtable_sizes.lock()).into_values().collect::<Vec<_>>();
-
-        // Primary sort: cost % in reverse order (from largest to smallest)
-        // Secondary sort: trait_name
-        infos.sort_by(|a, b| {
-            a.upcasting_cost_percent
-                .total_cmp(&b.upcasting_cost_percent)
-                .reverse()
-                .then_with(|| a.trait_name.cmp(&b.trait_name))
-        });
-
-        for VTableSizeInfo {
-            trait_name,
-            entries,
-            entries_ignoring_upcasting,
-            entries_for_upcasting,
-            upcasting_cost_percent,
-        } in infos
-        {
-            println!(
-                r#"print-vtable-sizes {{ "crate_name": "{crate_name}", "trait_name": "{trait_name}", "entries": "{entries}", "entries_ignoring_upcasting": "{entries_ignoring_upcasting}", "entries_for_upcasting": "{entries_for_upcasting}", "upcasting_cost_percent": "{upcasting_cost_percent}" }}"#
-            );
-        }
-    }
 }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 97bd2670aa6..2fb4b27b889 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -189,6 +189,39 @@ pub enum CoverageLevel {
     Mcdc,
 }
 
+/// The different settings that the `-Z autodiff` flag can have.
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum AutoDiff {
+    /// Print TypeAnalysis information
+    PrintTA,
+    /// Print ActivityAnalysis Information
+    PrintAA,
+    /// Print Performance Warnings from Enzyme
+    PrintPerf,
+    /// Combines the three print flags above.
+    Print,
+    /// Print the whole module, before running opts.
+    PrintModBefore,
+    /// Print the whole module just before we pass it to Enzyme.
+    /// For Debug purpose, prefer the OPT flag below
+    PrintModAfterOpts,
+    /// Print the module after Enzyme differentiated everything.
+    PrintModAfterEnzyme,
+
+    /// Enzyme's loose type debug helper (can cause incorrect gradients)
+    LooseTypes,
+
+    /// More flags
+    NoModOptAfter,
+    /// Tell Enzyme to run LLVM Opts on each function it generated. By default off,
+    /// since we already optimize the whole module after Enzyme is done.
+    EnableFncOpt,
+    NoVecUnroll,
+    RuntimeActivity,
+    /// Runs Enzyme specific Inlining
+    Inline,
+}
+
 /// Settings for `-Z instrument-xray` flag.
 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
 pub struct InstrumentXRay {
@@ -1191,6 +1224,7 @@ impl Default for Options {
             color: ColorConfig::Auto,
             logical_env: FxIndexMap::default(),
             verbose: false,
+            target_modifiers: BTreeMap::default(),
         }
     }
 }
@@ -1786,7 +1820,7 @@ pub fn parse_error_format(
                 ErrorOutputType::HumanReadable(HumanReadableErrorType::Unicode, color)
             }
             Some(arg) => {
-                early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
+                early_dcx.set_error_format(ErrorOutputType::HumanReadable(
                     HumanReadableErrorType::Default,
                     color,
                 ));
@@ -2327,7 +2361,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
 
     let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered);
 
-    early_dcx.abort_if_error_and_set_error_format(error_format);
+    early_dcx.set_error_format(error_format);
 
     let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
         early_dcx.early_fatal("`--diagnostic-width` must be an positive integer");
@@ -2337,14 +2371,16 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
         .unwrap_or_else(|e| early_dcx.early_fatal(e));
 
-    let mut unstable_opts = UnstableOptions::build(early_dcx, matches);
+    let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
+
+    let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
     let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
 
     check_error_format_stability(early_dcx, &unstable_opts, error_format);
 
     let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
 
-    let mut cg = CodegenOptions::build(early_dcx, matches);
+    let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
     let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
         early_dcx,
         &output_types,
@@ -2615,6 +2651,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
         color,
         logical_env,
         verbose,
+        target_modifiers,
     }
 }
 
@@ -2737,6 +2774,7 @@ pub mod nightly_options {
                         "the option `{}` is only accepted on the nightly compiler",
                         opt.name
                     );
+                    // The non-zero nightly_options_on_stable will force an early_fatal eventually.
                     let _ = early_dcx.early_err(msg);
                 }
                 OptionStability::Stable => {}
@@ -2902,7 +2940,7 @@ pub(crate) mod dep_tracking {
     };
 
     use super::{
-        BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
+        AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
         CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
         InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
         LtoCli, MirStripDebugInfo, NextSolverConfig, OomStrategy, OptLevel, OutFileName,
@@ -2950,6 +2988,7 @@ pub(crate) mod dep_tracking {
     }
 
     impl_dep_tracking_hash_via_hash!(
+        AutoDiff,
         bool,
         usize,
         NonZero<usize>,
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index dcf86d1a408..924350b8cbc 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -4,6 +4,9 @@
 #![feature(let_chains)]
 #![feature(map_many_mut)]
 #![feature(rustc_attrs)]
+// To generate CodegenOptionsTargetModifiers and UnstableOptionsTargetModifiers enums
+// with macro_rules, it is necessary to use recursive mechanic ("Incremental TT Munchers").
+#![recursion_limit = "256"]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 4ce63825129..4ed5499d32c 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -10,6 +10,7 @@ use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_data_structures::stable_hasher::Hash64;
 use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl};
 use rustc_feature::UnstableFeatures;
+use rustc_macros::{Decodable, Encodable};
 use rustc_span::edition::Edition;
 use rustc_span::{RealFileName, SourceFileHashAlgorithm};
 use rustc_target::spec::{
@@ -59,18 +60,194 @@ macro_rules! hash_substruct {
     };
 }
 
+/// Extended target modifier info.
+/// For example, when external target modifier is '-Zregparm=2':
+/// Target modifier enum value + user value ('2') from external crate
+/// is converted into description: prefix ('Z'), name ('regparm'), tech value ('Some(2)').
+pub struct ExtendedTargetModifierInfo {
+    /// Flag prefix (usually, 'C' for codegen flags or 'Z' for unstable flags)
+    pub prefix: String,
+    /// Flag name
+    pub name: String,
+    /// Flag parsed technical value
+    pub tech_value: String,
+}
+
+/// A recorded -Zopt_name=opt_value (or -Copt_name=opt_value)
+/// which alter the ABI or effectiveness of exploit mitigations.
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
+pub struct TargetModifier {
+    /// Option enum value
+    pub opt: OptionsTargetModifiers,
+    /// User-provided option value (before parsing)
+    pub value_name: String,
+}
+
+impl TargetModifier {
+    pub fn extend(&self) -> ExtendedTargetModifierInfo {
+        self.opt.reparse(&self.value_name)
+    }
+}
+
+fn tmod_push_impl(
+    opt: OptionsTargetModifiers,
+    tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
+    tmods: &mut Vec<TargetModifier>,
+) {
+    tmods.push(TargetModifier { opt, value_name: tmod_vals.get(&opt).cloned().unwrap_or_default() })
+}
+
+macro_rules! tmod_push {
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $mods:expr, $tmod_vals:expr) => {
+        tmod_push_impl(
+            OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name),
+            $tmod_vals,
+            $mods,
+        );
+    };
+}
+
+macro_rules! gather_tmods {
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+        [SUBSTRUCT], [TARGET_MODIFIER]) => {
+        compile_error!("SUBSTRUCT can't be target modifier");
+    };
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+        [UNTRACKED], [TARGET_MODIFIER]) => {
+        tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
+    };
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+        [TRACKED], [TARGET_MODIFIER]) => {
+        tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
+    };
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+        [TRACKED_NO_CRATE_HASH], [TARGET_MODIFIER]) => {
+        tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
+    };
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+        [SUBSTRUCT], []) => {
+        $opt_expr.gather_target_modifiers($mods, $tmod_vals);
+    };
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+        [UNTRACKED], []) => {{}};
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+        [TRACKED], []) => {{}};
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+        [TRACKED_NO_CRATE_HASH], []) => {{}};
+}
+
+macro_rules! gather_tmods_top_level {
+    ($_opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [SUBSTRUCT $substruct_enum:ident]) => {
+        $opt_expr.gather_target_modifiers($mods, $tmod_vals);
+    };
+    ($opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [$non_substruct:ident TARGET_MODIFIER]) => {
+        compile_error!("Top level option can't be target modifier");
+    };
+    ($opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [$non_substruct:ident]) => {};
+}
+
+/// Macro for generating OptionsTargetsModifiers top-level enum with impl.
+/// Will generate something like:
+/// ```rust,ignore (illustrative)
+/// pub enum OptionsTargetModifiers {
+///     CodegenOptions(CodegenOptionsTargetModifiers),
+///     UnstableOptions(UnstableOptionsTargetModifiers),
+/// }
+/// impl OptionsTargetModifiers {
+///     pub fn reparse(&self, user_value: &str) -> ExtendedTargetModifierInfo {
+///         match self {
+///             Self::CodegenOptions(v) => v.reparse(user_value),
+///             Self::UnstableOptions(v) => v.reparse(user_value),
+///         }
+///     }
+///     pub fn is_target_modifier(flag_name: &str) -> bool {
+///         CodegenOptionsTargetModifiers::is_target_modifier(flag_name) ||
+///         UnstableOptionsTargetModifiers::is_target_modifier(flag_name)
+///     }
+/// }
+/// ```
+macro_rules! top_level_tmod_enum {
+    ($( {$($optinfo:tt)*} ),* $(,)*) => {
+        top_level_tmod_enum! { @parse {}, (user_value){}; $($($optinfo)*|)* }
+    };
+    // Termination
+    (
+        @parse
+        {$($variant:tt($substruct_enum:tt))*},
+        ($user_value:ident){$($pout:tt)*};
+    ) => {
+        #[allow(non_camel_case_types)]
+        #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)]
+        pub enum OptionsTargetModifiers {
+            $($variant($substruct_enum)),*
+        }
+        impl OptionsTargetModifiers {
+            #[allow(unused_variables)]
+            pub fn reparse(&self, $user_value: &str) -> ExtendedTargetModifierInfo {
+                #[allow(unreachable_patterns)]
+                match self {
+                    $($pout)*
+                    _ => panic!("unknown target modifier option: {:?}", *self)
+                }
+            }
+            pub fn is_target_modifier(flag_name: &str) -> bool {
+                $($substruct_enum::is_target_modifier(flag_name))||*
+            }
+        }
+    };
+    // Adding SUBSTRUCT option group into $eout
+    (
+        @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
+            [SUBSTRUCT $substruct_enum:ident $variant:ident] |
+        $($tail:tt)*
+    ) => {
+        top_level_tmod_enum! {
+            @parse
+            {
+                $($eout)*
+                $variant($substruct_enum)
+            },
+            ($puser_value){
+                $($pout)*
+                Self::$variant(v) => v.reparse($puser_value),
+            };
+            $($tail)*
+        }
+    };
+    // Skipping non-target-modifier and non-substruct
+    (
+        @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
+            [$non_substruct:ident] |
+        $($tail:tt)*
+    ) => {
+        top_level_tmod_enum! {
+            @parse
+            {
+                $($eout)*
+            },
+            ($puser_value){
+                $($pout)*
+            };
+            $($tail)*
+        }
+    };
+}
+
 macro_rules! top_level_options {
     ( $( #[$top_level_attr:meta] )* pub struct Options { $(
         $( #[$attr:meta] )*
-        $opt:ident : $t:ty [$dep_tracking_marker:ident],
+        $opt:ident : $t:ty [$dep_tracking_marker:ident $( $tmod:ident $variant:ident )?],
     )* } ) => (
+        top_level_tmod_enum!( {$([$dep_tracking_marker $($tmod $variant),*])|*} );
+
         #[derive(Clone)]
         $( #[$top_level_attr] )*
         pub struct Options {
             $(
                 $( #[$attr] )*
                 pub $opt: $t
-            ),*
+            ),*,
+            pub target_modifiers: BTreeMap<OptionsTargetModifiers, String>,
         }
 
         impl Options {
@@ -98,6 +275,17 @@ macro_rules! top_level_options {
                 })*
                 hasher.finish()
             }
+
+            pub fn gather_target_modifiers(&self) -> Vec<TargetModifier> {
+                let mut mods = Vec::<TargetModifier>::new();
+                $({
+                    gather_tmods_top_level!($opt,
+                        &self.$opt, &mut mods, &self.target_modifiers,
+                        [$dep_tracking_marker $($tmod),*]);
+                })*
+                mods.sort_by(|a, b| a.opt.cmp(&b.opt));
+                mods
+            }
         }
     );
 }
@@ -165,9 +353,9 @@ top_level_options!(
         #[rustc_lint_opt_deny_field_access("should only be used via `Config::hash_untracked_state`")]
         untracked_state_hash: Hash64 [TRACKED_NO_CRATE_HASH],
 
-        unstable_opts: UnstableOptions [SUBSTRUCT],
+        unstable_opts: UnstableOptions [SUBSTRUCT UnstableOptionsTargetModifiers UnstableOptions],
         prints: Vec<PrintRequest> [UNTRACKED],
-        cg: CodegenOptions [SUBSTRUCT],
+        cg: CodegenOptions [SUBSTRUCT CodegenOptionsTargetModifiers CodegenOptions],
         externs: Externs [UNTRACKED],
         crate_name: Option<String> [TRACKED],
         /// Indicates how the compiler should treat unstable features.
@@ -226,6 +414,98 @@ top_level_options!(
     }
 );
 
+macro_rules! tmod_enum_opt {
+    ($struct_name:ident, $tmod_enum_name:ident, $opt:ident, $v:ident) => {
+        Some(OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt))
+    };
+    ($struct_name:ident, $tmod_enum_name:ident, $opt:ident, ) => {
+        None
+    };
+}
+
+macro_rules! tmod_enum {
+    ($tmod_enum_name:ident, $prefix:expr, $( {$($optinfo:tt)*} ),* $(,)*) => {
+        tmod_enum! { $tmod_enum_name, $prefix, @parse {}, (user_value){}; $($($optinfo)*|)* }
+    };
+    // Termination
+    (
+        $tmod_enum_name:ident, $prefix:expr,
+        @parse
+        {$($eout:tt)*},
+        ($user_value:ident){$($pout:tt)*};
+    ) => {
+        #[allow(non_camel_case_types)]
+        #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)]
+        pub enum $tmod_enum_name {
+            $($eout),*
+        }
+        impl $tmod_enum_name {
+            #[allow(unused_variables)]
+            pub fn reparse(&self, $user_value: &str) -> ExtendedTargetModifierInfo {
+                #[allow(unreachable_patterns)]
+                match self {
+                    $($pout)*
+                    _ => panic!("unknown target modifier option: {:?}", *self)
+                }
+            }
+            pub fn is_target_modifier(flag_name: &str) -> bool {
+                match flag_name.replace('-', "_").as_str() {
+                    $(stringify!($eout) => true,)*
+                    _ => false,
+                }
+            }
+        }
+    };
+    // Adding target-modifier option into $eout
+    (
+        $tmod_enum_name:ident, $prefix:expr,
+        @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
+            $opt:ident, $parse:ident, $t:ty, [TARGET_MODIFIER] |
+        $($tail:tt)*
+    ) => {
+        tmod_enum! {
+            $tmod_enum_name, $prefix,
+            @parse
+            {
+                $($eout)*
+                $opt
+            },
+            ($puser_value){
+                $($pout)*
+                Self::$opt => {
+                    let mut parsed : $t = Default::default();
+                    parse::$parse(&mut parsed, Some($puser_value));
+                    ExtendedTargetModifierInfo {
+                        prefix: $prefix.to_string(),
+                        name: stringify!($opt).to_string().replace('_', "-"),
+                        tech_value: format!("{:?}", parsed),
+                    }
+                },
+            };
+            $($tail)*
+        }
+    };
+    // Skipping non-target-modifier
+    (
+        $tmod_enum_name:ident, $prefix:expr,
+        @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
+            $opt:ident, $parse:ident, $t:ty, [] |
+        $($tail:tt)*
+    ) => {
+        tmod_enum! {
+            $tmod_enum_name, $prefix,
+            @parse
+            {
+                $($eout)*
+            },
+            ($puser_value){
+                $($pout)*
+            };
+            $($tail)*
+        }
+    };
+}
+
 /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
 /// macro is to define an interface that can be programmatically used by the option parser
 /// to initialize the struct without hardcoding field names all over the place.
@@ -235,11 +515,11 @@ top_level_options!(
 /// generated code to parse an option into its respective field in the struct. There are a few
 /// hand-written parsers for parsing specific types of values in this module.
 macro_rules! options {
-    ($struct_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr,
+    ($struct_name:ident, $tmod_enum_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr,
      $($( #[$attr:meta] )* $opt:ident : $t:ty = (
         $init:expr,
         $parse:ident,
-        [$dep_tracking_marker:ident],
+        [$dep_tracking_marker:ident $( $tmod:ident )?],
         $desc:expr
         $(, deprecated_do_nothing: $dnn:literal )?)
      ),* ,) =>
@@ -248,6 +528,8 @@ macro_rules! options {
     #[rustc_lint_opt_ty]
     pub struct $struct_name { $( $( #[$attr] )* pub $opt: $t),* }
 
+    tmod_enum!( $tmod_enum_name, $prefix, {$($opt, $parse, $t, [$($tmod),*])|*} );
+
     impl Default for $struct_name {
         fn default() -> $struct_name {
             $struct_name { $($opt: $init),* }
@@ -258,8 +540,9 @@ macro_rules! options {
         pub fn build(
             early_dcx: &EarlyDiagCtxt,
             matches: &getopts::Matches,
+            target_modifiers: &mut BTreeMap<OptionsTargetModifiers, String>,
         ) -> $struct_name {
-            build_options(early_dcx, matches, $stat, $prefix, $outputname)
+            build_options(early_dcx, matches, target_modifiers, $stat, $prefix, $outputname)
         }
 
         fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
@@ -279,11 +562,23 @@ macro_rules! options {
                                         );
             hasher.finish()
         }
+
+        pub fn gather_target_modifiers(
+            &self,
+            _mods: &mut Vec<TargetModifier>,
+            _tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
+        ) {
+            $({
+                gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, _mods, _tmod_vals,
+                    [$dep_tracking_marker], [$($tmod),*]);
+            })*
+        }
     }
 
     pub const $stat: OptionDescrs<$struct_name> =
         &[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt,
-            type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )? } ),* ];
+            type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )?,
+            tmod: tmod_enum_opt!($struct_name, $tmod_enum_name, $opt, $($tmod),*) } ),* ];
 
     mod $optmod {
     $(
@@ -328,6 +623,7 @@ pub struct OptionDesc<O> {
     // description for option from options table
     desc: &'static str,
     is_deprecated_and_do_nothing: bool,
+    tmod: Option<OptionsTargetModifiers>,
 }
 
 impl<O> OptionDesc<O> {
@@ -344,6 +640,7 @@ impl<O> OptionDesc<O> {
 fn build_options<O: Default>(
     early_dcx: &EarlyDiagCtxt,
     matches: &getopts::Matches,
+    target_modifiers: &mut BTreeMap<OptionsTargetModifiers, String>,
     descrs: OptionDescrs<O>,
     prefix: &str,
     outputname: &str,
@@ -357,7 +654,14 @@ fn build_options<O: Default>(
 
         let option_to_lookup = key.replace('-', "_");
         match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) {
-            Some(OptionDesc { name: _, setter, type_desc, desc, is_deprecated_and_do_nothing }) => {
+            Some(OptionDesc {
+                name: _,
+                setter,
+                type_desc,
+                desc,
+                is_deprecated_and_do_nothing,
+                tmod,
+            }) => {
                 if *is_deprecated_and_do_nothing {
                     // deprecation works for prefixed options only
                     assert!(!prefix.is_empty());
@@ -377,6 +681,11 @@ fn build_options<O: Default>(
                         ),
                     }
                 }
+                if let Some(tmod) = *tmod
+                    && let Some(value) = value
+                {
+                    target_modifiers.insert(tmod, value.to_string());
+                }
             }
             None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")),
         }
@@ -398,6 +707,7 @@ mod desc {
     pub(crate) const parse_list: &str = "a space-separated list of strings";
     pub(crate) const parse_list_with_polarity: &str =
         "a comma-separated list of strings, with elements beginning with + or -";
+    pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Print`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfterOpts`, `PrintModAfterEnzyme`, `LooseTypes`, `NoModOptAfter`, `EnableFncOpt`, `NoVecUnroll`, `Inline`";
     pub(crate) const parse_comma_list: &str = "a comma-separated list of strings";
     pub(crate) const parse_opt_comma_list: &str = parse_comma_list;
     pub(crate) const parse_number: &str = "a number";
@@ -1029,6 +1339,38 @@ pub mod parse {
         }
     }
 
+    pub(crate) fn parse_autodiff(slot: &mut Vec<AutoDiff>, v: Option<&str>) -> bool {
+        let Some(v) = v else {
+            *slot = vec![];
+            return true;
+        };
+        let mut v: Vec<&str> = v.split(",").collect();
+        v.sort_unstable();
+        for &val in v.iter() {
+            let variant = match val {
+                "PrintTA" => AutoDiff::PrintTA,
+                "PrintAA" => AutoDiff::PrintAA,
+                "PrintPerf" => AutoDiff::PrintPerf,
+                "Print" => AutoDiff::Print,
+                "PrintModBefore" => AutoDiff::PrintModBefore,
+                "PrintModAfterOpts" => AutoDiff::PrintModAfterOpts,
+                "PrintModAfterEnzyme" => AutoDiff::PrintModAfterEnzyme,
+                "LooseTypes" => AutoDiff::LooseTypes,
+                "NoModOptAfter" => AutoDiff::NoModOptAfter,
+                "EnableFncOpt" => AutoDiff::EnableFncOpt,
+                "NoVecUnroll" => AutoDiff::NoVecUnroll,
+                "Inline" => AutoDiff::Inline,
+                _ => {
+                    // FIXME(ZuseZ4): print an error saying which value is not recognized
+                    return false;
+                }
+            };
+            slot.push(variant);
+        }
+
+        true
+    }
+
     pub(crate) fn parse_instrument_coverage(
         slot: &mut InstrumentCoverage,
         v: Option<&str>,
@@ -1581,7 +1923,7 @@ pub mod parse {
 }
 
 options! {
-    CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen",
+    CodegenOptions, CodegenOptionsTargetModifiers, CG_OPTIONS, cgopts, "C", "codegen",
 
     // If you add a new option, please update:
     // - compiler/rustc_interface/src/tests.rs
@@ -1712,6 +2054,8 @@ options! {
     target_feature: String = (String::new(), parse_target_feature, [TRACKED],
         "target specific attributes. (`rustc --print target-features` for details). \
         This feature is unsafe."),
+    unsafe_allow_abi_mismatch: Vec<String> = (Vec::new(), parse_comma_list, [UNTRACKED],
+        "Allow incompatible target modifiers in dependency crates (comma separated list)"),
     // tidy-alphabetical-end
 
     // If you add a new option, please update:
@@ -1720,7 +2064,7 @@ options! {
 }
 
 options! {
-    UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable",
+    UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable",
 
     // If you add a new option, please update:
     // - compiler/rustc_interface/src/tests.rs
@@ -1736,6 +2080,22 @@ options! {
          either `loaded` or `not-loaded`."),
     assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
         "make cfg(version) treat the current version as incomplete (default: no)"),
+    autodiff: Vec<crate::config::AutoDiff> = (Vec::new(), parse_autodiff, [TRACKED],
+        "a list of optional autodiff flags to enable
+         Optional extra settings:
+         `=PrintTA`
+         `=PrintAA`
+         `=PrintPerf`
+         `=Print`
+         `=PrintModBefore`
+         `=PrintModAfterOpts`
+         `=PrintModAfterEnzyme`
+         `=LooseTypes`
+         `=NoModOptAfter`
+         `=EnableFncOpt`
+         `=NoVecUnroll`
+         `=Inline`
+         Multiple options can be combined with commas."),
     #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")]
     binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
         "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
@@ -1803,6 +2163,7 @@ options! {
         "output statistics about monomorphization collection"),
     dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
         "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
+    #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")]
     dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
         "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
     dylib_lto: bool = (false, parse_bool, [UNTRACKED],
@@ -2033,8 +2394,6 @@ options! {
          Note that this overwrites the effect `-Clink-dead-code` has on collection!"),
     print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
         "print layout information for each type encountered (default: no)"),
-    print_vtable_sizes: bool = (false, parse_bool, [UNTRACKED],
-        "print size comparison between old and new vtable layouts (default: no)"),
     proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
          "show backtraces for panics during proc-macro execution (default: no)"),
     proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread,
@@ -2050,10 +2409,10 @@ options! {
         "enable queries of the dependency graph for regression testing (default: no)"),
     randomize_layout: bool = (false, parse_bool, [TRACKED],
         "randomize the layout of types (default: no)"),
-    reg_struct_return: bool = (false, parse_bool, [TRACKED],
+    reg_struct_return: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
         "On x86-32 targets, it overrides the default ABI to return small structs in registers.
         It is UNSOUND to link together crates that use different values for this flag!"),
-    regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
+    regparm: Option<u32> = (None, parse_opt_number, [TRACKED TARGET_MODIFIER],
         "On x86-32 targets, setting this to N causes the compiler to pass N arguments \
         in registers EAX, EDX, and ECX instead of on the stack for\
         \"C\", \"cdecl\", and \"stdcall\" fn.\
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 90361efed84..81ae06602cd 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -277,14 +277,10 @@ impl ParseSess {
     ) -> Self {
         let fallback_bundle = fallback_fluent_bundle(locale_resources, false);
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-        let emitter = Box::new(HumanEmitter::new(
-            stderr_destination(ColorConfig::Auto),
-            Lrc::clone(&fallback_bundle),
-        ));
-        let fatal_dcx = DiagCtxt::new(emitter);
+        let fatal_emitter =
+            Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle));
         let dcx = DiagCtxt::new(Box::new(SilentEmitter {
-            fallback_bundle,
-            fatal_dcx,
+            fatal_emitter,
             fatal_note: Some(fatal_note),
             emit_fatal_diagnostic,
         }))
@@ -341,8 +337,4 @@ impl ParseSess {
     pub fn dcx(&self) -> DiagCtxtHandle<'_> {
         self.dcx.handle()
     }
-
-    pub fn set_dcx(&mut self, dcx: DiagCtxt) {
-        self.dcx = dcx;
-    }
 }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 1f03de3f53d..2b79081a26e 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -732,6 +732,11 @@ impl Session {
         self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
     }
 
+    /// Returns the DWARF version passed on the CLI or the default for the target.
+    pub fn dwarf_version(&self) -> u32 {
+        self.opts.unstable_opts.dwarf_version.unwrap_or(self.target.default_dwarf_version)
+    }
+
     pub fn stack_protector(&self) -> StackProtector {
         if self.target.options.supports_stack_protector {
             self.opts.unstable_opts.stack_protector
@@ -1263,8 +1268,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     }
 
     if sess.opts.unstable_opts.embed_source {
-        let dwarf_version =
-            sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version);
+        let dwarf_version = sess.dwarf_version();
 
         if dwarf_version < 5 {
             sess.dcx().emit_warn(errors::EmbedSourceInsufficientDwarfVersion { dwarf_version });
@@ -1358,12 +1362,6 @@ pub struct EarlyDiagCtxt {
     dcx: DiagCtxt,
 }
 
-impl Default for EarlyDiagCtxt {
-    fn default() -> Self {
-        Self::new(ErrorOutputType::default())
-    }
-}
-
 impl EarlyDiagCtxt {
     pub fn new(output: ErrorOutputType) -> Self {
         let emitter = mk_emitter(output);
@@ -1371,10 +1369,9 @@ impl EarlyDiagCtxt {
     }
 
     /// Swap out the underlying dcx once we acquire the user's preference on error emission
-    /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the
-    /// previous dcx will be emitted.
-    pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) {
-        self.dcx.handle().abort_if_errors();
+    /// format. If `early_err` was previously called this will panic.
+    pub fn set_error_format(&mut self, output: ErrorOutputType) {
+        assert!(self.dcx.handle().has_errors().is_none());
 
         let emitter = mk_emitter(output);
         self.dcx = DiagCtxt::new(emitter);
@@ -1394,7 +1391,7 @@ impl EarlyDiagCtxt {
 
     #[allow(rustc::untranslatable_diagnostic)]
     #[allow(rustc::diagnostic_outside_of_impl)]
-    #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
+    #[must_use = "raise_fatal must be called on the returned ErrorGuaranteed in order to exit with a non-zero status code"]
     pub fn early_err(&self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
         self.dcx.handle().err(msg)
     }
diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs
index 4e8db6096d4..52c5b425c14 100644
--- a/compiler/rustc_smir/src/rustc_smir/alloc.rs
+++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs
@@ -1,6 +1,6 @@
 use rustc_abi::{Align, Size};
 use rustc_middle::mir::ConstValue;
-use rustc_middle::mir::interpret::{AllocRange, Pointer, alloc_range};
+use rustc_middle::mir::interpret::{AllocInit, AllocRange, Pointer, alloc_range};
 use stable_mir::Error;
 use stable_mir::mir::Mutability;
 use stable_mir::ty::{Allocation, ProvenanceMap};
@@ -44,7 +44,8 @@ pub(crate) fn try_new_allocation<'tcx>(
                 .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
                 .map_err(|e| e.stable(tables))?
                 .align;
-            let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
+            let mut allocation =
+                rustc_middle::mir::interpret::Allocation::new(size, align.abi, AllocInit::Uninit);
             allocation
                 .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar)
                 .map_err(|e| e.stable(tables))?;
@@ -68,8 +69,11 @@ pub(crate) fn try_new_allocation<'tcx>(
                 .tcx
                 .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
                 .map_err(|e| e.stable(tables))?;
-            let mut allocation =
-                rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi);
+            let mut allocation = rustc_middle::mir::interpret::Allocation::new(
+                layout.size,
+                layout.align.abi,
+                AllocInit::Uninit,
+            );
             allocation
                 .write_scalar(
                     &tables.tcx,
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 31c7e6c3eb4..cdc56782a26 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -450,8 +450,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         let ty = ty::Ty::new_static_str(tcx);
         let bytes = value.as_bytes();
-        let val_tree = ty::ValTree::from_raw_bytes(tcx, bytes);
-        let val = tcx.valtree_to_const_val((ty, val_tree));
+        let valtree = ty::ValTree::from_raw_bytes(tcx, bytes);
+        let cv = ty::Value { ty, valtree };
+        let val = tcx.valtree_to_const_val(cv);
         mir::Const::from_value(val, ty).stable(&mut tables)
     }
 
@@ -746,7 +747,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         let alloc_id = tables.tcx.vtable_allocation((
             ty.internal(&mut *tables, tcx),
-            trait_ref.internal(&mut *tables, tcx),
+            trait_ref
+                .internal(&mut *tables, tcx)
+                .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
         ));
         Some(alloc_id.stable(&mut *tables))
     }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index aee98d7d410..4a0420cc603 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -217,6 +217,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
                 stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
             }
             CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
+            WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
         }
     }
 }
@@ -395,6 +396,7 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
             Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)),
             OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)),
             Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)),
+            UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
         }
     }
 }
@@ -496,6 +498,9 @@ impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> {
                     found: found.stable(tables),
                 }
             }
+            AssertKind::NullPointerDereference => {
+                stable_mir::mir::AssertMessage::NullPointerDereference
+            }
         }
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index ff452eea23d..a2d95f0f693 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -418,23 +418,16 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
     type T = stable_mir::ty::TyConst;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        let kind = match self.kind() {
-            ty::ConstKind::Value(ty, val) => {
-                let val = match val {
-                    ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar),
-                    ty::ValTree::Branch(branch) => {
-                        ty::ValTree::Branch(tables.tcx.lift(branch).unwrap())
-                    }
-                };
-
-                let ty = tables.tcx.lift(ty).unwrap();
-                let const_val = tables.tcx.valtree_to_const_val((ty, val));
+        let ct = tables.tcx.lift(*self).unwrap();
+        let kind = match ct.kind() {
+            ty::ConstKind::Value(cv) => {
+                let const_val = tables.tcx.valtree_to_const_val(cv);
                 if matches!(const_val, mir::ConstValue::ZeroSized) {
-                    stable_mir::ty::TyConstKind::ZSTValue(ty.stable(tables))
+                    stable_mir::ty::TyConstKind::ZSTValue(cv.ty.stable(tables))
                 } else {
                     stable_mir::ty::TyConstKind::Value(
-                        ty.stable(tables),
-                        alloc::new_allocation(ty, const_val, tables),
+                        cv.ty.stable(tables),
+                        alloc::new_allocation(cv.ty, const_val, tables),
                     )
                 }
             }
@@ -449,7 +442,7 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
             ty::ConstKind::Placeholder(_) => unimplemented!(),
             ty::ConstKind::Expr(_) => unimplemented!(),
         };
-        let id = tables.intern_ty_const(tables.tcx.lift(*self).unwrap());
+        let id = tables.intern_ty_const(ct);
         stable_mir::ty::TyConst::new(kind, id)
     }
 }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 51d809bd65d..b1f9f4a01c5 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -600,11 +600,43 @@ impl Span {
         !self.is_dummy() && sm.is_span_accessible(self)
     }
 
+    /// Returns whether `span` originates in a foreign crate's external macro.
+    ///
+    /// This is used to test whether a lint should not even begin to figure out whether it should
+    /// be reported on the current node.
+    pub fn in_external_macro(self, sm: &SourceMap) -> bool {
+        let expn_data = self.ctxt().outer_expn_data();
+        match expn_data.kind {
+            ExpnKind::Root
+            | ExpnKind::Desugaring(
+                DesugaringKind::ForLoop
+                | DesugaringKind::WhileLoop
+                | DesugaringKind::OpaqueTy
+                | DesugaringKind::Async
+                | DesugaringKind::Await,
+            ) => false,
+            ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
+            ExpnKind::Macro(MacroKind::Bang, _) => {
+                // Dummy span for the `def_site` means it's an external macro.
+                expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site)
+            }
+            ExpnKind::Macro { .. } => true, // definitely a plugin
+        }
+    }
+
     /// Returns `true` if `span` originates in a derive-macro's expansion.
     pub fn in_derive_expansion(self) -> bool {
         matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
     }
 
+    /// Return whether `span` is generated by `async` or `await`.
+    pub fn is_from_async_await(self) -> bool {
+        matches!(
+            self.ctxt().outer_expn_data().kind,
+            ExpnKind::Desugaring(DesugaringKind::Async | DesugaringKind::Await),
+        )
+    }
+
     /// Gate suggestions that would not be appropriate in a context the user didn't write.
     pub fn can_be_used_for_suggestions(self) -> bool {
         !self.from_expansion()
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 6f1d3a74a81..b23cc909911 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -314,8 +314,6 @@ symbols! {
         Right,
         Rust,
         RustaceansAreAwesome,
-        RustcDecodable,
-        RustcEncodable,
         RwLock,
         RwLockReadGuard,
         RwLockWriteGuard,
@@ -502,7 +500,6 @@ symbols! {
         augmented_assignments,
         auto_traits,
         autodiff,
-        autodiff_fallback,
         automatically_derived,
         avx,
         avx512_target_feature,
@@ -568,7 +565,6 @@ symbols! {
         cfg_accessible,
         cfg_attr,
         cfg_attr_multi,
-        cfg_autodiff_fallback,
         cfg_boolean_literals,
         cfg_doctest,
         cfg_emscripten_wasm_eh,
@@ -1476,6 +1472,7 @@ symbols! {
         panic_location,
         panic_misaligned_pointer_dereference,
         panic_nounwind,
+        panic_null_pointer_dereference,
         panic_runtime,
         panic_str_2015,
         panic_unwind,
@@ -2153,7 +2150,6 @@ symbols! {
         unwrap,
         unwrap_binder,
         unwrap_or,
-        unwrap_unsafe_binder,
         use_extern_macros,
         use_nested_groups,
         used,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 879f3fac21f..8ae35572d01 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -274,14 +274,15 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
     fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
         // only print integers
         match ct.kind() {
-            ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar)) if ty.is_integral() => {
+            ty::ConstKind::Value(cv) if cv.ty.is_integral() => {
                 // The `pretty_print_const` formatting depends on -Zverbose-internals
                 // flag, so we cannot reuse it here.
-                let signed = matches!(ty.kind(), ty::Int(_));
+                let scalar = cv.valtree.unwrap_leaf();
+                let signed = matches!(cv.ty.kind(), ty::Int(_));
                 write!(
                     self,
                     "{:#?}",
-                    ty::ConstInt::new(scalar, signed, ty.is_ptr_sized_integral())
+                    ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral())
                 )?;
             }
             _ => self.write_str("_")?,
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 5c5ab435dbd..4312c82815c 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -151,7 +151,7 @@ fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty
 
 pub fn typeid_for_trait_ref<'tcx>(
     tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyExistentialTraitRef<'tcx>,
+    trait_ref: ty::ExistentialTraitRef<'tcx>,
 ) -> String {
     v0::mangle_typeid_for_trait_ref(tcx, trait_ref)
 }
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 4ddf530a00d..7b040a8b2c4 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -72,7 +72,7 @@ pub(super) fn mangle<'tcx>(
 
 pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
     tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyExistentialTraitRef<'tcx>,
+    trait_ref: ty::ExistentialTraitRef<'tcx>,
 ) -> String {
     // FIXME(flip1995): See comment in `mangle_typeid_for_fnabi`.
     let mut cx = SymbolMangler {
@@ -84,7 +84,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
         binders: vec![],
         out: String::new(),
     };
-    cx.print_def_path(trait_ref.def_id(), &[]).unwrap();
+    cx.print_def_path(trait_ref.def_id, &[]).unwrap();
     std::mem::take(&mut cx.out)
 }
 
@@ -590,8 +590,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
 
     fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
         // We only mangle a typed value if the const can be evaluated.
-        let (ct_ty, valtree) = match ct.kind() {
-            ty::ConstKind::Value(ty, val) => (ty, val),
+        let cv = match ct.kind() {
+            ty::ConstKind::Value(cv) => cv,
 
             // Should only be encountered within the identity-substituted
             // impl header of an item nested within an impl item.
@@ -619,13 +619,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
             return Ok(());
         }
 
+        let ty::Value { ty: ct_ty, valtree } = cv;
         let start = self.out.len();
 
         match ct_ty.kind() {
             ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
                 ct_ty.print(self)?;
 
-                let mut bits = ct
+                let mut bits = cv
                     .try_to_bits(self.tcx, ty::TypingEnv::fully_monomorphized())
                     .expect("expected const to be monomorphic");
 
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 1292f46f0c9..f17452b3ba0 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -934,6 +934,7 @@ pub enum InlineAsmClobberAbi {
     LoongArch,
     PowerPC,
     S390x,
+    Bpf,
     Msp430,
 }
 
@@ -1003,6 +1004,10 @@ impl InlineAsmClobberAbi {
                 "C" | "system" => Ok(InlineAsmClobberAbi::S390x),
                 _ => Err(&["C", "system"]),
             },
+            InlineAsmArch::Bpf => match name {
+                "C" | "system" => Ok(InlineAsmClobberAbi::Bpf),
+                _ => Err(&["C", "system"]),
+            },
             InlineAsmArch::Msp430 => match name {
                 "C" | "system" => Ok(InlineAsmClobberAbi::Msp430),
                 _ => Err(&["C", "system"]),
@@ -1278,6 +1283,14 @@ impl InlineAsmClobberAbi {
                     a8, a9, a10, a11, a12, a13, a14, a15,
                 }
             },
+            InlineAsmClobberAbi::Bpf => clobbered_regs! {
+                Bpf BpfInlineAsmReg {
+                    // Refs: Section 1.1 "Registers and calling convention" in BPF ABI Recommended Conventions and Guidelines v1.0
+                    // https://www.kernel.org/doc/html/latest/bpf/standardization/abi.html#registers-and-calling-convention
+
+                    r0, r1, r2, r3, r4, r5,
+                }
+            },
             InlineAsmClobberAbi::Msp430 => clobbered_regs! {
                 Msp430 Msp430InlineAsmReg {
                     r11, r12, r13, r14, r15,
diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs
index 1ec22bbd73b..a6b0ec072e8 100644
--- a/compiler/rustc_target/src/spec/json.rs
+++ b/compiler/rustc_target/src/spec/json.rs
@@ -559,6 +559,7 @@ impl Target {
         key!(link_env_remove, list);
         key!(asm_args, list);
         key!(cpu);
+        key!(need_explicit_cpu, bool);
         key!(features);
         key!(dynamic_linking, bool);
         key!(direct_access_external_data, Option<bool>);
@@ -734,6 +735,7 @@ impl ToJson for Target {
         target_option_val!(link_env_remove);
         target_option_val!(asm_args);
         target_option_val!(cpu);
+        target_option_val!(need_explicit_cpu);
         target_option_val!(features);
         target_option_val!(dynamic_linking);
         target_option_val!(direct_access_external_data);
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index b029eae4b7d..72600225e7a 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -2281,6 +2281,9 @@ pub struct TargetOptions {
     /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
     /// to "generic".
     pub cpu: StaticCow<str>,
+    /// Whether a cpu needs to be explicitly set.
+    /// Set to true if there is no default cpu. Defaults to false.
+    pub need_explicit_cpu: bool,
     /// Default target features to pass to LLVM. These features overwrite
     /// `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`.
     /// Corresponds to `llc -mattr=$features`.
@@ -2715,6 +2718,7 @@ impl Default for TargetOptions {
             link_script: None,
             asm_args: cvs![],
             cpu: "generic".into(),
+            need_explicit_cpu: false,
             features: "".into(),
             direct_access_external_data: None,
             dynamic_linking: false,
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 9bcf2b7e3cf..5355a4ad532 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -135,6 +135,11 @@ const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("aclass", Unstable(sym::arm_target_feature), &[]),
     ("aes", Unstable(sym::arm_target_feature), &["neon"]),
+    (
+        "atomics-32",
+        Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" },
+        &[],
+    ),
     ("crc", Unstable(sym::arm_target_feature), &[]),
     ("d32", Unstable(sym::arm_target_feature), &[]),
     ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 750d2756b4a..055a3edcc32 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -148,8 +148,6 @@ trait_selection_dtcs_has_req_note = the used `impl` has a `'static` requirement
 trait_selection_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement
 trait_selection_dtcs_suggestion = consider relaxing the implicit `'static` requirement
 
-trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
-
 trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
     .label = empty on-clause here
 
@@ -165,6 +163,8 @@ trait_selection_explicit_lifetime_required_with_param_type = explicit lifetime r
 
 trait_selection_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
 
+trait_selection_fn_consider_casting_both = consider casting both fn items to fn pointers using `as {$sig}`
+
 trait_selection_fn_uniq_types = different fn items have unique types, even if their signatures are the same
 trait_selection_fps_cast = consider casting to a fn pointer
 trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 5f3f65e4696..091773009e9 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -435,7 +435,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
         terr: TypeError<'tcx>,
         param_env: Option<ParamEnv<'tcx>>,
-        path: &mut Option<PathBuf>,
     ) {
         match *cause.code() {
             ObligationCauseCode::Pattern {
@@ -458,7 +457,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             format!("this is an iterator with items of type `{}`", args.type_at(0)),
                         );
                     } else {
-                        let expected_ty = self.tcx.short_ty_string(expected_ty, path);
+                        let expected_ty = self.tcx.short_string(expected_ty, err.long_ty_path());
                         err.span_label(span, format!("this expression has type `{expected_ty}`"));
                     }
                 }
@@ -1392,9 +1391,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         mut values: Option<ty::ParamEnvAnd<'tcx, ValuePairs<'tcx>>>,
         terr: TypeError<'tcx>,
         prefer_label: bool,
+        override_span: Option<Span>,
     ) {
-        let span = cause.span;
-
+        // We use `override_span` when we want the error to point at a `Span` other than
+        // `cause.span`. This is used in E0271, when a closure is passed in where the return type
+        // isn't what was expected. We want to point at the closure's return type (or expression),
+        // instead of the expression where the closure is passed as call argument.
+        let span = override_span.unwrap_or(cause.span);
         // For some types of errors, expected-found does not make
         // sense, so just ignore the values we were given.
         if let TypeError::CyclicTy(_) = terr {
@@ -1541,7 +1544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         (false, Mismatch::Fixed("existential projection"))
                     }
                 };
-                let Some(vals) = self.values_str(values, cause) else {
+                let Some(vals) = self.values_str(values, cause, diag.long_ty_path()) else {
                     // Derived error. Cancel the emitter.
                     // NOTE(eddyb) this was `.cancel()`, but `diag`
                     // is borrowed, so we can't fully defuse it.
@@ -1596,9 +1599,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             return;
         }
 
-        let mut path = None;
-        if let Some((expected, found, p)) = expected_found {
-            path = p;
+        if let Some((expected, found)) = expected_found {
             let (expected_label, found_label, exp_found) = match exp_found {
                 Mismatch::Variable(ef) => (
                     ef.expected.prefix_string(self.tcx),
@@ -1721,32 +1722,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     }
                 }
                 TypeError::Sorts(values) => {
-                    let extra = expected == found;
+                    let extra = expected == found
+                        // Ensure that we don't ever say something like
+                        // expected `impl Trait` (opaque type `impl Trait`)
+                        //    found `impl Trait` (opaque type `impl Trait`)
+                        && values.expected.sort_string(self.tcx)
+                            != values.found.sort_string(self.tcx);
                     let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
                         (true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
                             let sm = self.tcx.sess.source_map();
                             let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
-                            format!(
+                            DiagStyledString::normal(format!(
                                 " (opaque type at <{}:{}:{}>)",
                                 sm.filename_for_diagnostics(&pos.file.name),
                                 pos.line,
                                 pos.col.to_usize() + 1,
-                            )
+                            ))
                         }
                         (true, ty::Alias(ty::Projection, proj))
                             if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
                         {
                             let sm = self.tcx.sess.source_map();
                             let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
-                            format!(
+                            DiagStyledString::normal(format!(
                                 " (trait associated opaque type at <{}:{}:{}>)",
                                 sm.filename_for_diagnostics(&pos.file.name),
                                 pos.line,
                                 pos.col.to_usize() + 1,
-                            )
+                            ))
                         }
-                        (true, _) => format!(" ({})", ty.sort_string(self.tcx)),
-                        (false, _) => "".to_string(),
+                        (true, _) => {
+                            let mut s = DiagStyledString::normal(" (");
+                            s.push_highlighted(ty.sort_string(self.tcx));
+                            s.push_normal(")");
+                            s
+                        }
+                        (false, _) => DiagStyledString::normal(""),
                     };
                     if !(values.expected.is_simple_text() && values.found.is_simple_text())
                         || (exp_found.is_some_and(|ef| {
@@ -1763,23 +1774,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             }
                         }))
                     {
-                        if let Some(ExpectedFound { found: found_ty, .. }) = exp_found {
+                        if let Some(ExpectedFound { found: found_ty, .. }) = exp_found
+                            && !self.tcx.ty_is_opaque_future(found_ty)
+                        {
                             // `Future` is a special opaque type that the compiler
                             // will try to hide in some case such as `async fn`, so
                             // to make an error more use friendly we will
                             // avoid to suggest a mismatch type with a
                             // type that the user usually are not using
                             // directly such as `impl Future<Output = u8>`.
-                            if !self.tcx.ty_is_opaque_future(found_ty) {
-                                diag.note_expected_found_extra(
-                                    &expected_label,
-                                    expected,
-                                    &found_label,
-                                    found,
-                                    &sort_string(values.expected),
-                                    &sort_string(values.found),
-                                );
-                            }
+                            diag.note_expected_found_extra(
+                                &expected_label,
+                                expected,
+                                &found_label,
+                                found,
+                                sort_string(values.expected),
+                                sort_string(values.found),
+                            );
                         }
                     }
                 }
@@ -1844,7 +1855,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 self.suggest_tuple_pattern(cause, &exp_found, diag);
                 self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
                 self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
-                self.suggest_function_pointers(cause, span, &exp_found, diag);
+                self.suggest_function_pointers(cause, span, &exp_found, terr, diag);
                 self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
             }
         }
@@ -1874,11 +1885,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         // It reads better to have the error origin as the final
         // thing.
-        self.note_error_origin(diag, cause, exp_found, terr, param_env, &mut path);
-        if let Some(path) = path {
-            diag.note(format!("the full type name has been written to '{}'", path.display()));
-            diag.note("consider using `--verbose` to print the full type name to the console");
-        }
+        self.note_error_origin(diag, cause, exp_found, terr, param_env);
 
         debug!(?diag);
     }
@@ -1887,6 +1894,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         &self,
         trace: &TypeTrace<'tcx>,
         terr: TypeError<'tcx>,
+        path: &mut Option<PathBuf>,
     ) -> Vec<TypeErrorAdditionalDiags> {
         let mut suggestions = Vec::new();
         let span = trace.cause.span;
@@ -1965,7 +1973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         })
         | ObligationCauseCode::BlockTailExpression(.., source)) = code
             && let hir::MatchSource::TryDesugar(_) = source
-            && let Some((expected_ty, found_ty, _)) = self.values_str(trace.values, &trace.cause)
+            && let Some((expected_ty, found_ty)) = self.values_str(trace.values, &trace.cause, path)
         {
             suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert {
                 found: found_ty.content(),
@@ -2023,14 +2031,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             _ => None,
         };
         if let Some(tykind) = tykind
-            && let hir::TyKind::Array(_, length) = tykind
-            && let Some((scalar, ty)) = sz.found.try_to_scalar()
-            && ty == self.tcx.types.usize
+            && let hir::TyKind::Array(_, length_arg) = tykind
+            && let Some(length_val) = sz.found.try_to_target_usize(self.tcx)
         {
-            let span = length.span();
             Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength {
-                span,
-                length: scalar.to_target_usize(&self.tcx).unwrap(),
+                span: length_arg.span(),
+                length: length_val,
             })
         } else {
             None
@@ -2046,12 +2052,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
 
         let span = trace.cause.span;
+        let mut path = None;
         let failure_code = trace.cause.as_failure_code_diag(
             terr,
             span,
-            self.type_error_additional_suggestions(&trace, terr),
+            self.type_error_additional_suggestions(&trace, terr, &mut path),
         );
         let mut diag = self.dcx().create_err(failure_code);
+        *diag.long_ty_path() = path;
         self.note_type_err(
             &mut diag,
             &trace.cause,
@@ -2059,6 +2067,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             Some(param_env.and(trace.values)),
             terr,
             false,
+            None,
         );
         diag
     }
@@ -2095,10 +2104,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         &self,
         values: ValuePairs<'tcx>,
         cause: &ObligationCause<'tcx>,
-    ) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
+        file: &mut Option<PathBuf>,
+    ) -> Option<(DiagStyledString, DiagStyledString)> {
         match values {
             ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
-            ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found),
+            ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, file),
             ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found),
             ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
             ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
@@ -2108,7 +2118,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     found: exp_found.found.print_trait_sugared(),
                 };
                 match self.expected_found_str(pretty_exp_found) {
-                    Some((expected, found, _)) if expected == found => {
+                    Some((expected, found)) if expected == found => {
                         self.expected_found_str(exp_found)
                     }
                     ret => ret,
@@ -2130,9 +2140,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     (None, None)
                 };
 
-                let (exp, fnd) =
-                    self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2);
-                Some((exp, fnd, None))
+                Some(self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2))
             }
         }
     }
@@ -2140,7 +2148,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     fn expected_found_str_term(
         &self,
         exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
-    ) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
+        path: &mut Option<PathBuf>,
+    ) -> Option<(DiagStyledString, DiagStyledString)> {
         let exp_found = self.resolve_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
@@ -2155,21 +2164,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 let len = self.tcx.sess().diagnostic_width() + 40;
                 let exp_s = exp.content();
                 let fnd_s = fnd.content();
-                let mut path = None;
                 if exp_s.len() > len {
-                    let exp_s = self.tcx.short_ty_string(expected, &mut path);
+                    let exp_s = self.tcx.short_string(expected, path);
                     exp = DiagStyledString::highlighted(exp_s);
                 }
                 if fnd_s.len() > len {
-                    let fnd_s = self.tcx.short_ty_string(found, &mut path);
+                    let fnd_s = self.tcx.short_string(found, path);
                     fnd = DiagStyledString::highlighted(fnd_s);
                 }
-                (exp, fnd, path)
+                (exp, fnd)
             }
             _ => (
                 DiagStyledString::highlighted(exp_found.expected.to_string()),
                 DiagStyledString::highlighted(exp_found.found.to_string()),
-                None,
             ),
         })
     }
@@ -2178,7 +2185,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     fn expected_found_str<T: fmt::Display + TypeFoldable<TyCtxt<'tcx>>>(
         &self,
         exp_found: ty::error::ExpectedFound<T>,
-    ) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
+    ) -> Option<(DiagStyledString, DiagStyledString)> {
         let exp_found = self.resolve_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
@@ -2187,7 +2194,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         Some((
             DiagStyledString::highlighted(exp_found.expected.to_string()),
             DiagStyledString::highlighted(exp_found.found.to_string()),
-            None,
         ))
     }
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index 68a53381230..99b70c87ccd 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -713,7 +713,7 @@ impl<'tcx> InferSourceKind<'tcx> {
                 if ty.is_closure() {
                     ("closure", closure_as_fn_str(infcx, ty), path)
                 } else if !ty.is_ty_or_numeric_infer() {
-                    ("normal", infcx.tcx.short_ty_string(ty, &mut path), path)
+                    ("normal", infcx.tcx.short_string(ty, &mut path), path)
                 } else {
                     ("other", String::new(), path)
                 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
deleted file mode 100644
index beae9962f7f..00000000000
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs
+++ /dev/null
@@ -1,422 +0,0 @@
-use rustc_errors::{Diag, Subdiagnostic};
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, IsSuggestable, Region, Ty};
-use rustc_span::kw;
-use tracing::debug;
-
-use super::ObligationCauseAsDiagArg;
-use crate::error_reporting::infer::{TypeErrCtxt, note_and_explain_region};
-use crate::errors::{
-    FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData,
-    RegionOriginNote, WhereClauseSuggestions, note_and_explain,
-};
-use crate::fluent_generated as fluent;
-use crate::infer::{self, SubregionOrigin};
-
-impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
-        match *origin {
-            infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
-                span: trace.cause.span,
-                requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
-                expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)),
-            }
-            .add_to_diag(err),
-            infer::Reborrow(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err)
-            }
-            infer::RelateObjectBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
-                    .add_to_diag(err);
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_reference_outlives_referent,
-                    name: &self.ty_to_string(ty),
-                    continues: false,
-                }
-                .add_to_diag(err);
-            }
-            infer::RelateParamBound(span, ty, opt_span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_relate_param_bound,
-                    name: &self.ty_to_string(ty),
-                    continues: opt_span.is_some(),
-                }
-                .add_to_diag(err);
-                if let Some(span) = opt_span {
-                    RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
-                        .add_to_diag(err);
-                }
-            }
-            infer::RelateRegionParamBound(span, _) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
-                    .add_to_diag(err);
-            }
-            infer::CompareImplItemObligation { span, .. } => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
-                    .add_to_diag(err);
-            }
-            infer::CheckAssociatedTypeBounds { ref parent, .. } => {
-                self.note_region_origin(err, parent);
-            }
-            infer::AscribeUserTypeProvePredicate(span) => {
-                RegionOriginNote::Plain {
-                    span,
-                    msg: fluent::infer_ascribe_user_type_prove_predicate,
-                }
-                .add_to_diag(err);
-            }
-        }
-    }
-
-    pub(super) fn report_concrete_failure(
-        &self,
-        generic_param_scope: LocalDefId,
-        origin: SubregionOrigin<'tcx>,
-        sub: Region<'tcx>,
-        sup: Region<'tcx>,
-    ) -> Diag<'a> {
-        let mut err = match origin {
-            infer::Subtype(box trace) => {
-                let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
-                let mut err = self.report_and_explain_type_error(trace, terr);
-                match (*sub, *sup) {
-                    (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
-                    (ty::RePlaceholder(_), _) => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            generic_param_scope,
-                            "",
-                            sup,
-                            " doesn't meet the lifetime requirements",
-                            None,
-                        );
-                    }
-                    (_, ty::RePlaceholder(_)) => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            generic_param_scope,
-                            "the required lifetime does not necessarily outlive ",
-                            sub,
-                            "",
-                            None,
-                        );
-                    }
-                    _ => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            generic_param_scope,
-                            "",
-                            sup,
-                            "...",
-                            None,
-                        );
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            generic_param_scope,
-                            "...does not necessarily outlive ",
-                            sub,
-                            "",
-                            None,
-                        );
-                    }
-                }
-                err
-            }
-            infer::Reborrow(span) => {
-                let reference_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::RefValidFor,
-                    note_and_explain::SuffixKind::Continues,
-                );
-                let content_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::ContentValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(OutlivesContent {
-                    span,
-                    notes: reference_valid.into_iter().chain(content_valid).collect(),
-                })
-            }
-            infer::RelateObjectBound(span) => {
-                let object_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::TypeObjValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                let pointer_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::SourcePointerValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(OutlivesBound {
-                    span,
-                    notes: object_valid.into_iter().chain(pointer_valid).collect(),
-                })
-            }
-            infer::RelateParamBound(span, ty, opt_span) => {
-                let prefix = match *sub {
-                    ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
-                    _ => note_and_explain::PrefixKind::TypeOutlive,
-                };
-                let suffix = if opt_span.is_some() {
-                    note_and_explain::SuffixKind::ReqByBinding
-                } else {
-                    note_and_explain::SuffixKind::Empty
-                };
-                let note = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    opt_span,
-                    prefix,
-                    suffix,
-                );
-                self.dcx().create_err(FulfillReqLifetime {
-                    span,
-                    ty: self.resolve_vars_if_possible(ty),
-                    note,
-                })
-            }
-            infer::RelateRegionParamBound(span, _) => {
-                let param_instantiated = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::LfParamInstantiatedWith,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                let param_must_outlive = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::LfParamMustOutlive,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(LfBoundNotSatisfied {
-                    span,
-                    notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
-                })
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                let pointer_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::PointerValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                let data_valid = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::DataValidFor,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(RefLongerThanData {
-                    span,
-                    ty: self.resolve_vars_if_possible(ty),
-                    notes: pointer_valid.into_iter().chain(data_valid).collect(),
-                })
-            }
-            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
-                let mut err = self.infcx.report_extra_impl_obligation(
-                    span,
-                    impl_item_def_id,
-                    trait_item_def_id,
-                    &format!("`{sup}: {sub}`"),
-                );
-                // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
-                if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
-                    && generics.where_clause_span.contains(span)
-                {
-                    self.suggest_copy_trait_method_bounds(
-                        trait_item_def_id,
-                        impl_item_def_id,
-                        &mut err,
-                    );
-                }
-                err
-            }
-            infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
-                let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup);
-
-                // Don't mention the item name if it's an RPITIT, since that'll just confuse
-                // folks.
-                if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) {
-                    let trait_item_span = self.tcx.def_span(trait_item_def_id);
-                    let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
-                    err.span_label(
-                        trait_item_span,
-                        format!("definition of `{item_name}` from trait"),
-                    );
-                }
-
-                self.suggest_copy_trait_method_bounds(
-                    trait_item_def_id,
-                    impl_item_def_id,
-                    &mut err,
-                );
-                err
-            }
-            infer::AscribeUserTypeProvePredicate(span) => {
-                let instantiated = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sup,
-                    None,
-                    note_and_explain::PrefixKind::LfInstantiatedWith,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                let must_outlive = note_and_explain::RegionExplanation::new(
-                    self.tcx,
-                    generic_param_scope,
-                    sub,
-                    None,
-                    note_and_explain::PrefixKind::LfMustOutlive,
-                    note_and_explain::SuffixKind::Empty,
-                );
-                self.dcx().create_err(LfBoundNotSatisfied {
-                    span,
-                    notes: instantiated.into_iter().chain(must_outlive).collect(),
-                })
-            }
-        };
-        if sub.is_error() || sup.is_error() {
-            err.downgrade_to_delayed_bug();
-        }
-        err
-    }
-
-    pub fn suggest_copy_trait_method_bounds(
-        &self,
-        trait_item_def_id: DefId,
-        impl_item_def_id: LocalDefId,
-        err: &mut Diag<'_>,
-    ) {
-        // FIXME(compiler-errors): Right now this is only being used for region
-        // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
-        // but right now it's not really very smart when it comes to implicit `Sized`
-        // predicates and bounds on the trait itself.
-
-        let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx)
-        else {
-            return;
-        };
-        let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else {
-            return;
-        };
-        let trait_args = trait_ref
-            .instantiate_identity()
-            // Replace the explicit self type with `Self` for better suggestion rendering
-            .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper))
-            .args;
-        let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id)
-            .rebase_onto(self.tcx, impl_def_id, trait_args);
-
-        let Ok(trait_predicates) =
-            self.tcx
-                .explicit_predicates_of(trait_item_def_id)
-                .instantiate_own(self.tcx, trait_item_args)
-                .map(|(pred, _)| {
-                    if pred.is_suggestable(self.tcx, false) {
-                        Ok(pred.to_string())
-                    } else {
-                        Err(())
-                    }
-                })
-                .collect::<Result<Vec<_>, ()>>()
-        else {
-            return;
-        };
-
-        let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else {
-            return;
-        };
-
-        let suggestion = if trait_predicates.is_empty() {
-            WhereClauseSuggestions::Remove { span: generics.where_clause_span }
-        } else {
-            let space = if generics.where_clause_span.is_empty() { " " } else { "" };
-            WhereClauseSuggestions::CopyPredicates {
-                span: generics.where_clause_span,
-                space,
-                trait_predicates: trait_predicates.join(", "),
-            }
-        };
-        err.subdiagnostic(suggestion);
-    }
-
-    pub(super) fn report_placeholder_failure(
-        &self,
-        generic_param_scope: LocalDefId,
-        placeholder_origin: SubregionOrigin<'tcx>,
-        sub: Region<'tcx>,
-        sup: Region<'tcx>,
-    ) -> Diag<'a> {
-        // I can't think how to do better than this right now. -nikomatsakis
-        debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
-        match placeholder_origin {
-            infer::Subtype(box ref trace)
-                if matches!(
-                    &trace.cause.code().peel_derives(),
-                    ObligationCauseCode::WhereClause(..)
-                        | ObligationCauseCode::WhereClauseInExpr(..)
-                ) =>
-            {
-                // Hack to get around the borrow checker because trace.cause has an `Rc`.
-                if let ObligationCauseCode::WhereClause(_, span)
-                | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
-                    &trace.cause.code().peel_derives()
-                    && !span.is_dummy()
-                {
-                    let span = *span;
-                    self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup)
-                        .with_span_note(span, "the lifetime requirement is introduced here")
-                } else {
-                    unreachable!(
-                        "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..."
-                    )
-                }
-            }
-            infer::Subtype(box trace) => {
-                let terr = TypeError::RegionsPlaceholderMismatch;
-                return self.report_and_explain_type_error(trace, terr);
-            }
-            _ => {
-                return self.report_concrete_failure(
-                    generic_param_scope,
-                    placeholder_origin,
-                    sub,
-                    sup,
-                );
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 3acca47025c..f35a5349ecb 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -221,7 +221,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
                 span: trace.cause.span,
                 requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
-                expected_found: self.values_str(trace.values, &trace.cause).map(|(e, f, _)| (e, f)),
+                expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()),
             }
             .add_to_diag(err),
             infer::Reborrow(span) => {
@@ -946,10 +946,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         if let infer::Subtype(ref sup_trace) = sup_origin
             && let infer::Subtype(ref sub_trace) = sub_origin
-            && let Some((sup_expected, sup_found, _)) =
-                self.values_str(sup_trace.values, &sup_trace.cause)
-            && let Some((sub_expected, sub_found, _)) =
-                self.values_str(sub_trace.values, &sup_trace.cause)
+            && let Some((sup_expected, sup_found)) =
+                self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path())
+            && let Some((sub_expected, sub_found)) =
+                self.values_str(sub_trace.values, &sup_trace.cause, err.long_ty_path())
             && sub_expected == sup_expected
             && sub_found == sup_found
         {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index af7e56961b7..562000e28ac 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -12,6 +12,7 @@ use rustc_middle::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
     StatementAsExpression,
 };
+use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
 use rustc_span::{Span, sym};
@@ -20,7 +21,7 @@ use tracing::debug;
 use crate::error_reporting::TypeErrCtxt;
 use crate::error_reporting::infer::hir::Path;
 use crate::errors::{
-    ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
+    ConsiderAddingAwait, FnConsiderCasting, FnConsiderCastingBoth, FnItemsAreDistinct, FnUniqTypes,
     FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding,
     SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags,
 };
@@ -381,14 +382,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
     }
 
-    pub(super) fn suggest_function_pointers(
+    pub fn suggest_function_pointers_impl(
         &self,
-        cause: &ObligationCause<'tcx>,
-        span: Span,
+        span: Option<Span>,
         exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
         diag: &mut Diag<'_>,
     ) {
-        debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
         let ty::error::ExpectedFound { expected, found } = exp_found;
         let expected_inner = expected.peel_refs();
         let found_inner = found.peel_refs();
@@ -411,8 +410,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     return;
                 }
 
+                let Some(span) = span else {
+                    let casting = format!("{fn_name} as {sig}");
+                    diag.subdiagnostic(FnItemsAreDistinct);
+                    diag.subdiagnostic(FnConsiderCasting { casting });
+                    return;
+                };
+
                 let sugg = match (expected.is_ref(), found.is_ref()) {
-                    (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
+                    (true, false) => {
+                        FunctionPointerSuggestion::UseRef { span: span.shrink_to_lo() }
+                    }
                     (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
                     (true, true) => {
                         diag.subdiagnostic(FnItemsAreDistinct);
@@ -420,7 +428,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     }
                     (false, false) => {
                         diag.subdiagnostic(FnItemsAreDistinct);
-                        FunctionPointerSuggestion::Cast { span, fn_name, sig }
+                        FunctionPointerSuggestion::Cast { span: span.shrink_to_hi(), sig }
                     }
                 };
                 diag.subdiagnostic(sugg);
@@ -445,6 +453,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
 
                 let fn_name = self.tcx.def_path_str_with_args(*did2, args2);
+
+                let Some(span) = span else {
+                    diag.subdiagnostic(FnConsiderCastingBoth { sig: *expected_sig });
+                    return;
+                };
+
                 let sug = if found.is_ref() {
                     FunctionPointerSuggestion::CastBothRef {
                         span,
@@ -454,8 +468,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     }
                 } else {
                     FunctionPointerSuggestion::CastBoth {
-                        span,
-                        fn_name,
+                        span: span.shrink_to_hi(),
                         found_sig: *found_sig,
                         expected_sig: *expected_sig,
                     }
@@ -488,6 +501,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         };
     }
 
+    pub(super) fn suggest_function_pointers(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        span: Span,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        terr: TypeError<'tcx>,
+        diag: &mut Diag<'_>,
+    ) {
+        debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
+
+        if exp_found.expected.peel_refs().is_fn() && exp_found.found.peel_refs().is_fn() {
+            self.suggest_function_pointers_impl(Some(span), exp_found, diag);
+        } else if let TypeError::Sorts(exp_found) = terr {
+            self.suggest_function_pointers_impl(None, &exp_found, diag);
+        }
+    }
+
     pub fn should_suggest_as_ref_kind(
         &self,
         expected: Ty<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index b4d294a70c0..6beb108bc3a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -163,6 +163,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         let predicate = self.resolve_vars_if_possible(obligation.predicate);
         let span = obligation.cause.span;
+        let mut file = None;
 
         debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
 
@@ -179,7 +180,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     return e;
                 }
 
-                if let Err(guar) = self.tcx.ensure().coherent_trait(trait_pred.def_id()) {
+                if let Err(guar) = self.tcx.ensure_ok().coherent_trait(trait_pred.def_id()) {
                     // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
                     // other `Foo` impls are incoherent.
                     return guar;
@@ -245,7 +246,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         span,
                         E0283,
                         "type annotations needed: cannot satisfy `{}`",
-                        predicate,
+                        self.tcx.short_string(predicate, &mut file),
                     )
                 };
 
@@ -292,7 +293,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         err.cancel();
                         return e;
                     }
-                    err.note(format!("cannot satisfy `{predicate}`"));
+                    let pred = self.tcx.short_string(predicate, &mut file);
+                    err.note(format!("cannot satisfy `{pred}`"));
                     let impl_candidates =
                         self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
                     if impl_candidates.len() < 40 {
@@ -511,8 +513,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     return e;
                 }
 
-                if let Err(guar) =
-                    self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_term.def_id))
+                if let Err(guar) = self
+                    .tcx
+                    .ensure_ok()
+                    .coherent_trait(self.tcx.parent(data.projection_term.def_id))
                 {
                     // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
                     // other `Foo` impls are incoherent.
@@ -524,6 +528,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     .iter()
                     .chain(Some(data.term.into_arg()))
                     .find(|g| g.has_non_region_infer());
+                let predicate = self.tcx.short_string(predicate, &mut file);
                 if let Some(arg) = arg {
                     self.emit_inference_failure_err(
                         obligation.cause.body_id,
@@ -539,8 +544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         self.dcx(),
                         span,
                         E0284,
-                        "type annotations needed: cannot satisfy `{}`",
-                        predicate,
+                        "type annotations needed: cannot satisfy `{predicate}`",
                     )
                     .with_span_label(span, format!("cannot satisfy `{predicate}`"))
                 }
@@ -565,12 +569,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     err
                 } else {
                     // If we can't find a generic parameter, just print a generic error
+                    let predicate = self.tcx.short_string(predicate, &mut file);
                     struct_span_code_err!(
                         self.dcx(),
                         span,
                         E0284,
-                        "type annotations needed: cannot satisfy `{}`",
-                        predicate,
+                        "type annotations needed: cannot satisfy `{predicate}`",
                     )
                     .with_span_label(span, format!("cannot satisfy `{predicate}`"))
                 }
@@ -590,6 +594,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 if let Some(e) = self.tainted_by_errors() {
                     return e;
                 }
+                let alias = self.tcx.short_string(alias, &mut file);
                 struct_span_code_err!(
                     self.dcx(),
                     span,
@@ -603,16 +608,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 if let Some(e) = self.tainted_by_errors() {
                     return e;
                 }
+                let predicate = self.tcx.short_string(predicate, &mut file);
                 struct_span_code_err!(
                     self.dcx(),
                     span,
                     E0284,
-                    "type annotations needed: cannot satisfy `{}`",
-                    predicate,
+                    "type annotations needed: cannot satisfy `{predicate}`",
                 )
                 .with_span_label(span, format!("cannot satisfy `{predicate}`"))
             }
         };
+        *err.long_ty_path() = file;
         self.note_obligation_cause(&mut err, obligation);
         err.emit()
     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 5021fd8bf83..87dcdcfd665 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1,5 +1,6 @@
 use core::ops::ControlFlow;
 use std::borrow::Cow;
+use std::path::PathBuf;
 
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::FxHashMap;
@@ -9,7 +10,6 @@ use rustc_errors::{
     Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions,
     pluralize, struct_span_code_err,
 };
-use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{self as hir, LangItem, Node};
@@ -20,8 +20,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::print::{
-    FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _,
-    PrintTraitRefExt as _, with_forced_trimmed_paths,
+    PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, PrintTraitRefExt as _,
+    with_forced_trimmed_paths,
 };
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast};
 use rustc_middle::{bug, span_bug};
@@ -60,6 +60,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     ) -> ErrorGuaranteed {
         let tcx = self.tcx;
         let mut span = obligation.cause.span;
+        let mut long_ty_file = None;
 
         let mut err = match *error {
             SelectionError::Unimplemented => {
@@ -169,11 +170,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         if let Err(guar) = self.fn_arg_obligation(&obligation) {
                             return guar;
                         }
-                        let mut file = None;
                         let (post_message, pre_message, type_def) = self
                             .get_parent_trait_ref(obligation.cause.code())
                             .map(|(t, s)| {
-                                let t = self.tcx.short_ty_string(t, &mut file);
+                                let t = self.tcx.short_string(t, &mut long_ty_file);
                                 (
                                     format!(" in `{t}`"),
                                     format!("within `{t}`, "),
@@ -181,12 +181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                 )
                             })
                             .unwrap_or_default();
-                        let file_note = file.as_ref().map(|file| format!(
-                            "the full trait has been written to '{}'",
-                            file.display(),
-                        ));
-
-                        let mut long_ty_file = None;
 
                         let OnUnimplementedNote {
                             message,
@@ -223,6 +217,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             None,
                             append_const_msg,
                             post_message,
+                            &mut long_ty_file,
                         );
 
                         let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)
@@ -251,14 +246,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         };
 
                         let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
+                        *err.long_ty_path() = long_ty_file;
 
-                        if let Some(long_ty_file) = long_ty_file {
-                            err.note(format!(
-                                "the full name for the type has been written to '{}'",
-                                long_ty_file.display(),
-                            ));
-                            err.note("consider using `--verbose` to print the full type name to the console");
-                        }
                         let mut suggested = false;
                         if is_try_conversion {
                             suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
@@ -309,7 +298,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             return err.emit();
                         }
 
-                        file_note.map(|note| err.note(note));
                         if let Some(s) = label {
                             // If it has a custom `#[rustc_on_unimplemented]`
                             // error message, let's display it as the label!
@@ -708,6 +696,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     None,
                     TypeError::Sorts(ty::error::ExpectedFound::new(expected_ty, ct_ty)),
                     false,
+                    None,
                 );
                 diag
             }
@@ -761,14 +750,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             trait_ref: predicate.trait_ref,
             polarity: ty::PredicatePolarity::Positive,
         });
+        let mut file = None;
         let err_msg = self.get_standard_error_message(
             trait_ref,
             None,
             Some(predicate.constness()),
             None,
             String::new(),
+            &mut file,
         );
         let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
+        *diag.long_ty_path() = file;
         if !self.predicate_may_hold(&Obligation::new(
             self.tcx,
             ObligationCause::dummy(),
@@ -931,14 +923,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
         }
         let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);
-        let body_id = match self.tcx.hir_node(hir_id) {
-            hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Fn { body: body_id, .. }, ..
-            }) => body_id,
-            _ => return false,
-        };
-        let ControlFlow::Break(expr) = (FindMethodSubexprOfTry { search_span: span })
-            .visit_body(self.tcx.hir().body(*body_id))
+        let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return false };
+        let ControlFlow::Break(expr) =
+            (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir().body(body_id))
         else {
             return false;
         };
@@ -1385,22 +1372,53 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 _ => (None, error.err),
             };
 
-            let msg = values
+            let mut file = None;
+            let (msg, span, closure_span) = values
                 .and_then(|(predicate, normalized_term, expected_term)| {
-                    self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
+                    self.maybe_detailed_projection_msg(
+                        obligation.cause.span,
+                        predicate,
+                        normalized_term,
+                        expected_term,
+                        &mut file,
+                    )
                 })
                 .unwrap_or_else(|| {
-                    let mut cx = FmtPrinter::new_with_limit(
-                        self.tcx,
-                        Namespace::TypeNS,
-                        rustc_session::Limit(10),
-                    );
-                    with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", {
-                        self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
-                        cx.into_buffer()
-                    }))
+                    (
+                        with_forced_trimmed_paths!(format!(
+                            "type mismatch resolving `{}`",
+                            self.tcx
+                                .short_string(self.resolve_vars_if_possible(predicate), &mut file),
+                        )),
+                        obligation.cause.span,
+                        None,
+                    )
                 });
-            let mut diag = struct_span_code_err!(self.dcx(), obligation.cause.span, E0271, "{msg}");
+            let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}");
+            *diag.long_ty_path() = file;
+            if let Some(span) = closure_span {
+                // Mark the closure decl so that it is seen even if we are pointing at the return
+                // type or expression.
+                //
+                // error[E0271]: expected `{closure@foo.rs:41:16}` to be a closure that returns
+                //               `Unit3`, but it returns `Unit4`
+                //   --> $DIR/foo.rs:43:17
+                //    |
+                // LL |     let v = Unit2.m(
+                //    |                   - required by a bound introduced by this call
+                // ...
+                // LL |             f: |x| {
+                //    |                --- /* this span */
+                // LL |                 drop(x);
+                // LL |                 Unit4
+                //    |                 ^^^^^ expected `Unit3`, found `Unit4`
+                //    |
+                diag.span_label(span, "this closure");
+                if !span.overlaps(obligation.cause.span) {
+                    // Point at the binding corresponding to the closure where it is used.
+                    diag.span_label(obligation.cause.span, "closure used here");
+                }
+            }
 
             let secondary_span = (|| {
                 let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
@@ -1443,15 +1461,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         ty.span,
                         with_forced_trimmed_paths!(Cow::from(format!(
                             "type mismatch resolving `{}`",
-                            {
-                                let mut cx = FmtPrinter::new_with_limit(
-                                    self.tcx,
-                                    Namespace::TypeNS,
-                                    rustc_session::Limit(5),
-                                );
-                                self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
-                                cx.into_buffer()
-                            }
+                            self.tcx.short_string(
+                                self.resolve_vars_if_possible(predicate),
+                                diag.long_ty_path()
+                            ),
                         ))),
                         true,
                     )),
@@ -1471,6 +1484,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }),
                 err,
                 false,
+                Some(span),
             );
             self.note_obligation_cause(&mut diag, obligation);
             diag.emit()
@@ -1479,34 +1493,65 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
     fn maybe_detailed_projection_msg(
         &self,
+        mut span: Span,
         projection_term: ty::AliasTerm<'tcx>,
         normalized_ty: ty::Term<'tcx>,
         expected_ty: ty::Term<'tcx>,
-    ) -> Option<String> {
+        file: &mut Option<PathBuf>,
+    ) -> Option<(String, Span, Option<Span>)> {
         let trait_def_id = projection_term.trait_def_id(self.tcx);
         let self_ty = projection_term.self_ty();
 
         with_forced_trimmed_paths! {
             if self.tcx.is_lang_item(projection_term.def_id, LangItem::FnOnceOutput) {
-                let fn_kind = self_ty.prefix_string(self.tcx);
+                let (span, closure_span) = if let ty::Closure(def_id, _) = self_ty.kind() {
+                    let def_span = self.tcx.def_span(def_id);
+                    if let Some(local_def_id) = def_id.as_local()
+                        && let node = self.tcx.hir_node_by_def_id(local_def_id)
+                        && let Some(fn_decl) = node.fn_decl()
+                        && let Some(id) = node.body_id()
+                    {
+                        span = match fn_decl.output {
+                            hir::FnRetTy::Return(ty) => ty.span,
+                            hir::FnRetTy::DefaultReturn(_) => {
+                                let body = self.tcx.hir().body(id);
+                                match body.value.kind {
+                                    hir::ExprKind::Block(
+                                        hir::Block { expr: Some(expr), .. },
+                                        _,
+                                    ) => expr.span,
+                                    hir::ExprKind::Block(
+                                        hir::Block {
+                                            expr: None, stmts: [.., last], ..
+                                        },
+                                        _,
+                                    ) => last.span,
+                                    _ => body.value.span,
+                                }
+                            }
+                        };
+                    }
+                    (span, Some(def_span))
+                } else {
+                    (span, None)
+                };
                 let item = match self_ty.kind() {
                     ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
-                    _ => self_ty.to_string(),
+                    _ => self.tcx.short_string(self_ty, file),
                 };
-                Some(format!(
-                    "expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \
-                     returns `{normalized_ty}`",
-                ))
+                Some((format!(
+                    "expected `{item}` to return `{expected_ty}`, but it returns `{normalized_ty}`",
+                ), span, closure_span))
             } else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) {
-                Some(format!(
+                Some((format!(
                     "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \
                      resolves to `{normalized_ty}`"
-                ))
+                ), span, None))
             } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
-                Some(format!(
+                Some((format!(
                     "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \
                      yields `{normalized_ty}`"
-                ))
+                ), span, None))
             } else {
                 None
             }
@@ -1923,8 +1968,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         StringPart::normal(" implemented for `"),
                     ]);
                     if types_content.0 == types_content.1 {
-                        let ty =
-                            self.tcx.short_ty_string(obligation_trait_ref.self_ty(), &mut None);
+                        let ty = self
+                            .tcx
+                            .short_string(obligation_trait_ref.self_ty(), err.long_ty_path());
                         msg.push(StringPart::normal(ty));
                     } else {
                         msg.extend(types.0.0);
@@ -1969,6 +2015,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             StringPart::highlighted(exp_found.found.to_string()),
                             StringPart::normal("`"),
                         ]);
+                        self.suggest_function_pointers_impl(None, &exp_found, err);
                     }
 
                     true
@@ -2280,7 +2327,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // First, attempt to add note to this error with an async-await-specific
         // message, and fall back to regular note otherwise.
         if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
-            let mut long_ty_file = None;
             self.note_obligation_cause_code(
                 obligation.cause.body_id,
                 err,
@@ -2289,15 +2335,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 obligation.cause.code(),
                 &mut vec![],
                 &mut Default::default(),
-                &mut long_ty_file,
             );
-            if let Some(file) = long_ty_file {
-                err.note(format!(
-                    "the full name for the type has been written to '{}'",
-                    file.display(),
-                ));
-                err.note("consider using `--verbose` to print the full type name to the console");
-            }
             self.suggest_unsized_bound_if_applicable(err, obligation);
             if let Some(span) = err.span.primary_span()
                 && let Some(mut diag) =
@@ -2341,6 +2379,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         predicate_constness: Option<ty::BoundConstness>,
         append_const_msg: Option<AppendConstMessage>,
         post_message: String,
+        long_ty_file: &mut Option<PathBuf>,
     ) -> String {
         message
             .and_then(|cannot_do_this| {
@@ -2364,7 +2403,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             .unwrap_or_else(|| {
                 format!(
                     "the trait bound `{}` is not satisfied{post_message}",
-                    trait_predicate.print_with_bound_constness(predicate_constness)
+                    self.tcx.short_string(
+                        trait_predicate.print_with_bound_constness(predicate_constness),
+                        long_ty_file,
+                    ),
                 )
             })
     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index 8111983c539..658fb4009d5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -306,7 +306,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 if let ObligationCauseCode::WhereClause(..)
                 | ObligationCauseCode::WhereClauseInExpr(..) = code
                 {
-                    let mut long_ty_file = None;
                     self.note_obligation_cause_code(
                         error.obligation.cause.body_id,
                         &mut diag,
@@ -315,17 +314,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         code,
                         &mut vec![],
                         &mut Default::default(),
-                        &mut long_ty_file,
                     );
-                    if let Some(file) = long_ty_file {
-                        diag.note(format!(
-                            "the full name for the type has been written to '{}'",
-                            file.display(),
-                        ));
-                        diag.note(
-                            "consider using `--verbose` to print the full type name to the console",
-                        );
-                    }
                 }
                 diag.emit()
             }
@@ -482,11 +471,10 @@ pub fn report_dyn_incompatibility<'tcx>(
     for (span, msg) in iter::zip(multi_span, messages) {
         note_span.push_span_label(span, msg);
     }
-    // FIXME(dyn_compat_renaming): Update the URL.
     err.span_note(
         note_span,
         "for a trait to be dyn compatible it needs to allow building a vtable\n\
-        for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
+        for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>",
     );
 
     // Only provide the help if its a local trait, otherwise it's not actionable.
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 3d79b0acf83..518323f6526 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -932,7 +932,7 @@ impl<'tcx> OnUnimplementedFormatString {
                 let value = match param.kind {
                     GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
                         if let Some(ty) = trait_ref.args[param.index as usize].as_type() {
-                            tcx.short_ty_string(ty, long_ty_file)
+                            tcx.short_string(ty, long_ty_file)
                         } else {
                             trait_ref.args[param.index as usize].to_string()
                         }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
index d82acc4e054..fad03b5e9bf 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
@@ -141,7 +141,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             obligation.cause.span,
             suggest_increasing_limit,
             |err| {
-                let mut long_ty_file = None;
                 self.note_obligation_cause_code(
                     obligation.cause.body_id,
                     err,
@@ -150,17 +149,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     obligation.cause.code(),
                     &mut vec![],
                     &mut Default::default(),
-                    &mut long_ty_file,
                 );
-                if let Some(file) = long_ty_file {
-                    err.note(format!(
-                        "the full name for the type has been written to '{}'",
-                        file.display(),
-                    ));
-                    err.note(
-                        "consider using `--verbose` to print the full type name to the console",
-                    );
-                }
             },
         );
     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index f9cda83a575..24ca7bb7fc2 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3,7 +3,6 @@
 use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::iter;
-use std::path::PathBuf;
 
 use itertools::{EitherOrBoth, Itertools};
 use rustc_abi::ExternAbi;
@@ -1297,30 +1296,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     // Because of this, we modify the error to refer to the original obligation and
                     // return early in the caller.
 
-                    let msg = format!("the trait bound `{old_pred}` is not satisfied");
+                    let msg = format!(
+                        "the trait bound `{}` is not satisfied",
+                        self.tcx.short_string(old_pred, err.long_ty_path()),
+                    );
+                    let self_ty_str =
+                        self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path());
                     if has_custom_message {
                         err.note(msg);
                     } else {
                         err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];
                     }
-                    let mut file = None;
                     err.span_label(
                         span,
                         format!(
-                            "the trait `{}` is not implemented for `{}`",
-                            old_pred.print_modifiers_and_trait_path(),
-                            self.tcx.short_ty_string(old_pred.self_ty().skip_binder(), &mut file),
+                            "the trait `{}` is not implemented for `{self_ty_str}`",
+                            old_pred.print_modifiers_and_trait_path()
                         ),
                     );
-                    if let Some(file) = file {
-                        err.note(format!(
-                            "the full type name has been written to '{}'",
-                            file.display()
-                        ));
-                        err.note(
-                            "consider using `--verbose` to print full type name to the console",
-                        );
-                    }
 
                     if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred {
                         err.span_suggestions(
@@ -2689,7 +2682,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // Add a note for the item obligation that remains - normally a note pointing to the
         // bound that introduced the obligation (e.g. `T: Send`).
         debug!(?next_code);
-        let mut long_ty_file = None;
         self.note_obligation_cause_code(
             obligation.cause.body_id,
             err,
@@ -2698,7 +2690,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             next_code.unwrap(),
             &mut Vec::new(),
             &mut Default::default(),
-            &mut long_ty_file,
         );
     }
 
@@ -2711,7 +2702,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         cause_code: &ObligationCauseCode<'tcx>,
         obligated_types: &mut Vec<Ty<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
-        long_ty_file: &mut Option<PathBuf>,
     ) where
         T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
     {
@@ -2769,6 +2759,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
+            ObligationCauseCode::ArrayLen(array_ty) => {
+                err.note(format!("the length of array `{array_ty}` must be type `usize`"));
+            }
             ObligationCauseCode::TupleElem => {
                 err.note("only the last element of a tuple may have a dynamically sized type");
             }
@@ -2962,9 +2955,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
             ObligationCauseCode::Coercion { source, target } => {
                 let source =
-                    tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file);
+                    tcx.short_string(self.resolve_vars_if_possible(source), err.long_ty_path());
                 let target =
-                    tcx.short_ty_string(self.resolve_vars_if_possible(target), long_ty_file);
+                    tcx.short_string(self.resolve_vars_if_possible(target), err.long_ty_path());
                 err.note(with_forced_trimmed_paths!(format!(
                     "required for the cast from `{source}` to `{target}`",
                 )));
@@ -3249,7 +3242,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 };
 
                 if !is_upvar_tys_infer_tuple {
-                    let ty_str = tcx.short_ty_string(ty, long_ty_file);
+                    let ty_str = tcx.short_string(ty, err.long_ty_path());
                     let msg = format!("required because it appears within the type `{ty_str}`");
                     match ty.kind() {
                         ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) {
@@ -3327,7 +3320,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             &data.parent_code,
                             obligated_types,
                             seen_requirements,
-                            long_ty_file,
                         )
                     });
                 } else {
@@ -3340,7 +3332,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             cause_code.peel_derives(),
                             obligated_types,
                             seen_requirements,
-                            long_ty_file,
                         )
                     });
                 }
@@ -3350,7 +3341,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     self.resolve_vars_if_possible(data.derived.parent_trait_pred);
                 let parent_def_id = parent_trait_pred.def_id();
                 let self_ty_str =
-                    tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
+                    tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path());
                 let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
                 let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
                 let mut is_auto_trait = false;
@@ -3446,8 +3437,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         count,
                         pluralize!(count)
                     ));
-                    let self_ty = tcx
-                        .short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
+                    let self_ty = tcx.short_string(
+                        parent_trait_pred.skip_binder().self_ty(),
+                        err.long_ty_path(),
+                    );
                     err.note(format!(
                         "required for `{self_ty}` to implement `{}`",
                         parent_trait_pred.print_modifiers_and_trait_path()
@@ -3463,7 +3456,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         &data.parent_code,
                         obligated_types,
                         seen_requirements,
-                        long_ty_file,
                     )
                 });
             }
@@ -3502,7 +3494,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         &data.derived.parent_code,
                         obligated_types,
                         seen_requirements,
-                        long_ty_file,
                     )
                 });
             }
@@ -3516,7 +3507,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         &data.parent_code,
                         obligated_types,
                         seen_requirements,
-                        long_ty_file,
                     )
                 });
             }
@@ -3533,7 +3523,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         &data.parent_code,
                         obligated_types,
                         seen_requirements,
-                        long_ty_file,
                     )
                 });
             }
@@ -3548,7 +3537,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         nested,
                         obligated_types,
                         seen_requirements,
-                        long_ty_file,
                     )
                 });
                 let mut multispan = MultiSpan::from(span);
@@ -3579,7 +3567,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         parent_code,
                         obligated_types,
                         seen_requirements,
-                        long_ty_file,
                     )
                 });
             }
@@ -3619,7 +3606,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
             ObligationCauseCode::OpaqueReturnType(expr_info) => {
                 let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info {
-                    let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file);
+                    let expr_ty = tcx.short_string(expr_ty, err.long_ty_path());
                     let expr = tcx.hir().expect_expr(hir_id);
                     (expr_ty, expr)
                 } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id()
@@ -3634,7 +3621,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     && let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
                     && self.can_eq(param_env, pred.self_ty(), expr_ty)
                 {
-                    let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file);
+                    let expr_ty = tcx.short_string(expr_ty, err.long_ty_path());
                     (expr_ty, expr)
                 } else {
                     return;
@@ -5228,7 +5215,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
             format!(
                 "{pre_message}the trait `{}` is not implemented for{desc} `{}`",
                 trait_predicate.print_modifiers_and_trait_path(),
-                tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None),
+                tcx.short_string(trait_predicate.self_ty().skip_binder(), &mut None),
             )
         } else {
             // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 2dfa72972ba..62cac5b17bd 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -12,7 +12,7 @@ use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
 use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
-use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt};
+use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, Region, Ty, TyCtxt};
 use rustc_span::{BytePos, Ident, Span, Symbol, kw};
 
 use crate::error_reporting::infer::ObligationCauseAsDiagArg;
@@ -23,15 +23,6 @@ use crate::fluent_generated as fluent;
 pub mod note_and_explain;
 
 #[derive(Diagnostic)]
-#[diag(trait_selection_dump_vtable_entries)]
-pub struct DumpVTableEntries<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub trait_ref: PolyTraitRef<'a>,
-    pub entries: String,
-}
-
-#[derive(Diagnostic)]
 #[diag(trait_selection_unable_to_construct_constant_value)]
 pub struct UnableToConstructConstantValue<'a> {
     #[primary_span]
@@ -1400,15 +1391,13 @@ pub struct OpaqueCapturesLifetime<'tcx> {
 pub enum FunctionPointerSuggestion<'a> {
     #[suggestion(
         trait_selection_fps_use_ref,
-        code = "&{fn_name}",
+        code = "&",
         style = "verbose",
         applicability = "maybe-incorrect"
     )]
     UseRef {
         #[primary_span]
         span: Span,
-        #[skip_arg]
-        fn_name: String,
     },
     #[suggestion(
         trait_selection_fps_remove_ref,
@@ -1438,7 +1427,7 @@ pub enum FunctionPointerSuggestion<'a> {
     },
     #[suggestion(
         trait_selection_fps_cast,
-        code = "{fn_name} as {sig}",
+        code = " as {sig}",
         style = "verbose",
         applicability = "maybe-incorrect"
     )]
@@ -1446,13 +1435,11 @@ pub enum FunctionPointerSuggestion<'a> {
         #[primary_span]
         span: Span,
         #[skip_arg]
-        fn_name: String,
-        #[skip_arg]
         sig: Binder<'a, FnSig<'a>>,
     },
     #[suggestion(
         trait_selection_fps_cast_both,
-        code = "{fn_name} as {found_sig}",
+        code = " as {found_sig}",
         style = "hidden",
         applicability = "maybe-incorrect"
     )]
@@ -1460,8 +1447,6 @@ pub enum FunctionPointerSuggestion<'a> {
         #[primary_span]
         span: Span,
         #[skip_arg]
-        fn_name: String,
-        #[skip_arg]
         found_sig: Binder<'a, FnSig<'a>>,
         expected_sig: Binder<'a, FnSig<'a>>,
     },
@@ -1497,6 +1482,12 @@ pub struct FnConsiderCasting {
 }
 
 #[derive(Subdiagnostic)]
+#[help(trait_selection_fn_consider_casting_both)]
+pub struct FnConsiderCastingBoth<'a> {
+    pub sig: Binder<'a, FnSig<'a>>,
+}
+
+#[derive(Subdiagnostic)]
 pub enum SuggestAccessingField<'a> {
     #[suggestion(
         trait_selection_suggest_accessing_field,
diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs
index 863b6e293ff..55171754618 100644
--- a/compiler/rustc_trait_selection/src/regions.rs
+++ b/compiler/rustc_trait_selection/src/regions.rs
@@ -1,10 +1,73 @@
+use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferCtxt, RegionResolutionError};
 use rustc_macros::extension;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::query::NoSolution;
+use rustc_middle::ty::{self, Ty};
 
 use crate::traits::ScrubbedTraitError;
+use crate::traits::outlives_bounds::InferCtxtExt;
+
+#[extension(pub trait OutlivesEnvironmentBuildExt<'tcx>)]
+impl<'tcx> OutlivesEnvironment<'tcx> {
+    fn new(
+        infcx: &InferCtxt<'tcx>,
+        body_id: LocalDefId,
+        param_env: ty::ParamEnv<'tcx>,
+        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
+    ) -> Self {
+        Self::new_with_implied_bounds_compat(
+            infcx,
+            body_id,
+            param_env,
+            assumed_wf_tys,
+            !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat,
+        )
+    }
+
+    fn new_with_implied_bounds_compat(
+        infcx: &InferCtxt<'tcx>,
+        body_id: LocalDefId,
+        param_env: ty::ParamEnv<'tcx>,
+        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
+        implied_bounds_compat: bool,
+    ) -> Self {
+        let mut bounds = vec![];
+
+        for bound in param_env.caller_bounds() {
+            if let Some(mut type_outlives) = bound.as_type_outlives_clause() {
+                if infcx.next_trait_solver() {
+                    match crate::solve::deeply_normalize::<_, ScrubbedTraitError<'tcx>>(
+                        infcx.at(&ObligationCause::dummy(), param_env),
+                        type_outlives,
+                    ) {
+                        Ok(new) => type_outlives = new,
+                        Err(_) => {
+                            infcx.dcx().delayed_bug(format!("could not normalize `{bound}`"));
+                        }
+                    }
+                }
+                bounds.push(type_outlives);
+            }
+        }
+
+        // FIXME: This needs to be modified so that we normalize the known type
+        // outlives obligations then elaborate them into their region/type components.
+        // Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even
+        // if we can normalize `'a`.
+        OutlivesEnvironment::from_normalized_bounds(
+            param_env,
+            bounds,
+            infcx.implied_bounds_tys_with_compat(
+                body_id,
+                param_env,
+                assumed_wf_tys,
+                implied_bounds_compat,
+            ),
+        )
+    }
+}
 
 #[extension(pub trait InferCtxtRegionExt<'tcx>)]
 impl<'tcx> InferCtxt<'tcx> {
@@ -16,9 +79,24 @@ impl<'tcx> InferCtxt<'tcx> {
     /// doing something specific for normalization.
     fn resolve_regions(
         &self,
+        body_id: LocalDefId,
+        param_env: ty::ParamEnv<'tcx>,
+        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
+    ) -> Vec<RegionResolutionError<'tcx>> {
+        self.resolve_regions_with_outlives_env(&OutlivesEnvironment::new(
+            self,
+            body_id,
+            param_env,
+            assumed_wf_tys,
+        ))
+    }
+
+    /// Don't call this directly unless you know what you're doing.
+    fn resolve_regions_with_outlives_env(
+        &self,
         outlives_env: &OutlivesEnvironment<'tcx>,
     ) -> Vec<RegionResolutionError<'tcx>> {
-        self.resolve_regions_with_normalize(outlives_env, |ty, origin| {
+        self.resolve_regions_with_normalize(&outlives_env, |ty, origin| {
             let ty = self.resolve_vars_if_possible(ty);
 
             if self.next_trait_solver() {
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index acd00d9f74f..abb79493432 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -1,7 +1,7 @@
 use std::ops::Deref;
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
@@ -98,9 +98,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         param_env: ty::ParamEnv<'tcx>,
         arg: ty::GenericArg<'tcx>,
     ) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> {
-        crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg).map(|obligations| {
-            obligations.into_iter().map(|obligation| obligation.into()).collect()
-        })
+        crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg, DUMMY_SP, CRATE_DEF_ID)
+            .map(|obligations| {
+                obligations.into_iter().map(|obligation| obligation.into()).collect()
+            })
     }
 
     fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 2b7da4bc5ff..0db44eda847 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -1,25 +1,21 @@
 use std::marker::PhantomData;
 use std::mem;
-use std::ops::ControlFlow;
 
 use rustc_data_structures::thinvec::ExtractIf;
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
-use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
 use rustc_infer::traits::{
-    self, FromSolverError, MismatchedProjectionTypes, Obligation, ObligationCause,
-    ObligationCauseCode, PredicateObligation, PredicateObligations, SelectionError, TraitEngine,
+    FromSolverError, PredicateObligation, PredicateObligations, TraitEngine,
 };
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_middle::{bug, span_bug};
 use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _};
-use tracing::{instrument, trace};
+use tracing::instrument;
 
+use self::derive_errors::*;
 use super::Certainty;
 use super::delegate::SolverDelegate;
-use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
-use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError};
+use crate::traits::{FulfillmentError, ScrubbedTraitError};
+
+mod derive_errors;
 
 /// A trait engine using the new trait solver.
 ///
@@ -244,483 +240,3 @@ impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for ScrubbedTraitError<'
         }
     }
 }
-
-fn fulfillment_error_for_no_solution<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    root_obligation: PredicateObligation<'tcx>,
-) -> FulfillmentError<'tcx> {
-    let obligation = find_best_leaf_obligation(infcx, &root_obligation, false);
-
-    let code = match obligation.predicate.kind().skip_binder() {
-        ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
-            FulfillmentErrorCode::Project(
-                // FIXME: This could be a `Sorts` if the term is a type
-                MismatchedProjectionTypes { err: TypeError::Mismatch },
-            )
-        }
-        ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, expected_ty)) => {
-            let ct_ty = match ct.kind() {
-                ty::ConstKind::Unevaluated(uv) => {
-                    infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
-                }
-                ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env),
-                ty::ConstKind::Value(ty, _) => ty,
-                kind => span_bug!(
-                    obligation.cause.span,
-                    "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}"
-                ),
-            };
-            FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType {
-                ct,
-                ct_ty,
-                expected_ty,
-            })
-        }
-        ty::PredicateKind::NormalizesTo(..) => {
-            FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
-        }
-        ty::PredicateKind::AliasRelate(_, _, _) => {
-            FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
-        }
-        ty::PredicateKind::Subtype(pred) => {
-            let (a, b) = infcx.enter_forall_and_leak_universe(
-                obligation.predicate.kind().rebind((pred.a, pred.b)),
-            );
-            let expected_found = ExpectedFound::new(a, b);
-            FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
-        }
-        ty::PredicateKind::Coerce(pred) => {
-            let (a, b) = infcx.enter_forall_and_leak_universe(
-                obligation.predicate.kind().rebind((pred.a, pred.b)),
-            );
-            let expected_found = ExpectedFound::new(b, a);
-            FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
-        }
-        ty::PredicateKind::Clause(_)
-        | ty::PredicateKind::DynCompatible(_)
-        | ty::PredicateKind::Ambiguous => {
-            FulfillmentErrorCode::Select(SelectionError::Unimplemented)
-        }
-        ty::PredicateKind::ConstEquate(..) => {
-            bug!("unexpected goal: {obligation:?}")
-        }
-    };
-
-    FulfillmentError { obligation, code, root_obligation }
-}
-
-fn fulfillment_error_for_stalled<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    root_obligation: PredicateObligation<'tcx>,
-) -> FulfillmentError<'tcx> {
-    let (code, refine_obligation) = infcx.probe(|_| {
-        match <&SolverDelegate<'tcx>>::from(infcx)
-            .evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No)
-            .0
-        {
-            Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
-                (FulfillmentErrorCode::Ambiguity { overflow: None }, true)
-            }
-            Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => (
-                FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
-                // Don't look into overflows because we treat overflows weirdly anyways.
-                // We discard the inference constraints from overflowing goals, so
-                // recomputing the goal again during `find_best_leaf_obligation` may apply
-                // inference guidance that makes other goals go from ambig -> pass, for example.
-                //
-                // FIXME: We should probably just look into overflows here.
-                false,
-            ),
-            Ok((_, Certainty::Yes)) => {
-                bug!("did not expect successful goal when collecting ambiguity errors")
-            }
-            Err(_) => {
-                bug!("did not expect selection error when collecting ambiguity errors")
-            }
-        }
-    });
-
-    FulfillmentError {
-        obligation: if refine_obligation {
-            find_best_leaf_obligation(infcx, &root_obligation, true)
-        } else {
-            root_obligation.clone()
-        },
-        code,
-        root_obligation,
-    }
-}
-
-fn fulfillment_error_for_overflow<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    root_obligation: PredicateObligation<'tcx>,
-) -> FulfillmentError<'tcx> {
-    FulfillmentError {
-        obligation: find_best_leaf_obligation(infcx, &root_obligation, true),
-        code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
-        root_obligation,
-    }
-}
-
-fn find_best_leaf_obligation<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    obligation: &PredicateObligation<'tcx>,
-    consider_ambiguities: bool,
-) -> PredicateObligation<'tcx> {
-    let obligation = infcx.resolve_vars_if_possible(obligation.clone());
-    // FIXME: we use a probe here as the `BestObligation` visitor does not
-    // check whether it uses candidates which get shadowed by where-bounds.
-    //
-    // We should probably fix the visitor to not do so instead, as this also
-    // means the leaf obligation may be incorrect.
-    infcx
-        .fudge_inference_if_ok(|| {
-            infcx
-                .visit_proof_tree(obligation.clone().into(), &mut BestObligation {
-                    obligation: obligation.clone(),
-                    consider_ambiguities,
-                })
-                .break_value()
-                .ok_or(())
-        })
-        .unwrap_or(obligation)
-}
-
-struct BestObligation<'tcx> {
-    obligation: PredicateObligation<'tcx>,
-    consider_ambiguities: bool,
-}
-
-impl<'tcx> BestObligation<'tcx> {
-    fn with_derived_obligation(
-        &mut self,
-        derived_obligation: PredicateObligation<'tcx>,
-        and_then: impl FnOnce(&mut Self) -> <Self as ProofTreeVisitor<'tcx>>::Result,
-    ) -> <Self as ProofTreeVisitor<'tcx>>::Result {
-        let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation);
-        let res = and_then(self);
-        self.obligation = old_obligation;
-        res
-    }
-
-    /// Filter out the candidates that aren't interesting to visit for the
-    /// purposes of reporting errors. For ambiguities, we only consider
-    /// candidates that may hold. For errors, we only consider candidates that
-    /// *don't* hold and which have impl-where clauses that also don't hold.
-    fn non_trivial_candidates<'a>(
-        &self,
-        goal: &'a inspect::InspectGoal<'a, 'tcx>,
-    ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> {
-        let mut candidates = goal.candidates();
-        match self.consider_ambiguities {
-            true => {
-                // If we have an ambiguous obligation, we must consider *all* candidates
-                // that hold, or else we may guide inference causing other goals to go
-                // from ambig -> pass/fail.
-                candidates.retain(|candidate| candidate.result().is_ok());
-            }
-            false => {
-                // If we have >1 candidate, one may still be due to "boring" reasons, like
-                // an alias-relate that failed to hold when deeply evaluated. We really
-                // don't care about reasons like this.
-                if candidates.len() > 1 {
-                    candidates.retain(|candidate| {
-                        goal.infcx().probe(|_| {
-                            candidate.instantiate_nested_goals(self.span()).iter().any(
-                                |nested_goal| {
-                                    matches!(
-                                        nested_goal.source(),
-                                        GoalSource::ImplWhereBound
-                                            | GoalSource::AliasBoundConstCondition
-                                            | GoalSource::InstantiateHigherRanked
-                                            | GoalSource::AliasWellFormed
-                                    ) && match self.consider_ambiguities {
-                                        true => {
-                                            matches!(
-                                                nested_goal.result(),
-                                                Ok(Certainty::Maybe(MaybeCause::Ambiguity))
-                                            )
-                                        }
-                                        false => matches!(nested_goal.result(), Err(_)),
-                                    }
-                                },
-                            )
-                        })
-                    });
-                }
-
-                // Prefer a non-rigid candidate if there is one.
-                if candidates.len() > 1 {
-                    candidates.retain(|candidate| {
-                        !matches!(candidate.kind(), inspect::ProbeKind::RigidAlias { .. })
-                    });
-                }
-            }
-        }
-
-        candidates
-    }
-}
-
-impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
-    type Result = ControlFlow<PredicateObligation<'tcx>>;
-
-    fn span(&self) -> rustc_span::Span {
-        self.obligation.cause.span
-    }
-
-    #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
-    fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
-        let candidates = self.non_trivial_candidates(goal);
-        trace!(candidates = ?candidates.iter().map(|c| c.kind()).collect::<Vec<_>>());
-
-        let [candidate] = candidates.as_slice() else {
-            return ControlFlow::Break(self.obligation.clone());
-        };
-
-        // Don't walk into impls that have `do_not_recommend`.
-        if let inspect::ProbeKind::TraitCandidate {
-            source: CandidateSource::Impl(impl_def_id),
-            result: _,
-        } = candidate.kind()
-            && goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
-        {
-            return ControlFlow::Break(self.obligation.clone());
-        }
-
-        let tcx = goal.infcx().tcx;
-        // FIXME: Also, what about considering >1 layer up the stack? May be necessary
-        // for normalizes-to.
-        let pred_kind = goal.goal().predicate.kind();
-        let child_mode = match pred_kind.skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
-                ChildMode::Trait(pred_kind.rebind(pred))
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => {
-                ChildMode::Host(pred_kind.rebind(pred))
-            }
-            ty::PredicateKind::NormalizesTo(normalizes_to)
-                if matches!(
-                    normalizes_to.alias.kind(tcx),
-                    ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst
-                ) =>
-            {
-                ChildMode::Trait(pred_kind.rebind(ty::TraitPredicate {
-                    trait_ref: normalizes_to.alias.trait_ref(tcx),
-                    polarity: ty::PredicatePolarity::Positive,
-                }))
-            }
-            _ => ChildMode::PassThrough,
-        };
-
-        let nested_goals = candidate.instantiate_nested_goals(self.span());
-
-        // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as
-        // an actual candidate, instead we should treat them as if the impl was never considered to
-        // have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written
-        // instead of `impl<T: FnPtr> Trait for T`.
-        //
-        // We do this as a separate loop so that we do not choose to tell the user about some nested
-        // goal before we encounter a `T: FnPtr` nested goal.
-        for nested_goal in &nested_goals {
-            if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait()
-                && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
-                && poly_trait_pred.def_id() == fn_ptr_trait
-                && let Err(NoSolution) = nested_goal.result()
-            {
-                return ControlFlow::Break(self.obligation.clone());
-            }
-        }
-
-        let mut impl_where_bound_count = 0;
-        for nested_goal in nested_goals {
-            trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
-
-            let make_obligation = |cause| Obligation {
-                cause,
-                param_env: nested_goal.goal().param_env,
-                predicate: nested_goal.goal().predicate,
-                recursion_depth: self.obligation.recursion_depth + 1,
-            };
-
-            let obligation;
-            match (child_mode, nested_goal.source()) {
-                (ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => {
-                    continue;
-                }
-                (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
-                    obligation = make_obligation(derive_cause(
-                        tcx,
-                        candidate.kind(),
-                        self.obligation.cause.clone(),
-                        impl_where_bound_count,
-                        parent_trait_pred,
-                    ));
-                    impl_where_bound_count += 1;
-                }
-                (
-                    ChildMode::Host(parent_host_pred),
-                    GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
-                ) => {
-                    obligation = make_obligation(derive_host_cause(
-                        tcx,
-                        candidate.kind(),
-                        self.obligation.cause.clone(),
-                        impl_where_bound_count,
-                        parent_host_pred,
-                    ));
-                    impl_where_bound_count += 1;
-                }
-                // Skip over a higher-ranked predicate.
-                (_, GoalSource::InstantiateHigherRanked) => {
-                    obligation = self.obligation.clone();
-                }
-                (ChildMode::PassThrough, _)
-                | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
-                    obligation = make_obligation(self.obligation.cause.clone());
-                }
-            }
-
-            // Skip nested goals that aren't the *reason* for our goal's failure.
-            match self.consider_ambiguities {
-                true if matches!(
-                    nested_goal.result(),
-                    Ok(Certainty::Maybe(MaybeCause::Ambiguity))
-                ) => {}
-                false if matches!(nested_goal.result(), Err(_)) => {}
-                _ => continue,
-            }
-
-            self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
-        }
-
-        // alias-relate may fail because the lhs or rhs can't be normalized,
-        // and therefore is treated as rigid.
-        if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred_kind.no_bound_vars() {
-            if let Some(obligation) = goal
-                .infcx()
-                .visit_proof_tree_at_depth(
-                    goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())),
-                    goal.depth() + 1,
-                    self,
-                )
-                .break_value()
-            {
-                return ControlFlow::Break(obligation);
-            } else if let Some(obligation) = goal
-                .infcx()
-                .visit_proof_tree_at_depth(
-                    goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())),
-                    goal.depth() + 1,
-                    self,
-                )
-                .break_value()
-            {
-                return ControlFlow::Break(obligation);
-            }
-        }
-
-        ControlFlow::Break(self.obligation.clone())
-    }
-}
-
-#[derive(Debug, Copy, Clone)]
-enum ChildMode<'tcx> {
-    // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
-    // and skip all `GoalSource::Misc`, which represent useless obligations
-    // such as alias-eq which may not hold.
-    Trait(ty::PolyTraitPredicate<'tcx>),
-    // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
-    // and skip all `GoalSource::Misc`, which represent useless obligations
-    // such as alias-eq which may not hold.
-    Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
-    // Skip trying to derive an `ObligationCause` from this obligation, and
-    // report *all* sub-obligations as if they came directly from the parent
-    // obligation.
-    PassThrough,
-}
-
-fn derive_cause<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
-    mut cause: ObligationCause<'tcx>,
-    idx: usize,
-    parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
-) -> ObligationCause<'tcx> {
-    match candidate_kind {
-        inspect::ProbeKind::TraitCandidate {
-            source: CandidateSource::Impl(impl_def_id),
-            result: _,
-        } => {
-            if let Some((_, span)) =
-                tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
-            {
-                cause = cause.derived_cause(parent_trait_pred, |derived| {
-                    ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
-                        derived,
-                        impl_or_alias_def_id: impl_def_id,
-                        impl_def_predicate_index: Some(idx),
-                        span,
-                    }))
-                })
-            }
-        }
-        inspect::ProbeKind::TraitCandidate {
-            source: CandidateSource::BuiltinImpl(..),
-            result: _,
-        } => {
-            cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived);
-        }
-        _ => {}
-    };
-    cause
-}
-
-fn derive_host_cause<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
-    mut cause: ObligationCause<'tcx>,
-    idx: usize,
-    parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
-) -> ObligationCause<'tcx> {
-    match candidate_kind {
-        inspect::ProbeKind::TraitCandidate {
-            source: CandidateSource::Impl(impl_def_id),
-            result: _,
-        } => {
-            if let Some((_, span)) = tcx
-                .predicates_of(impl_def_id)
-                .instantiate_identity(tcx)
-                .into_iter()
-                .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
-                    |(trait_ref, span)| {
-                        (
-                            trait_ref.to_host_effect_clause(
-                                tcx,
-                                parent_host_pred.skip_binder().constness,
-                            ),
-                            span,
-                        )
-                    },
-                ))
-                .nth(idx)
-            {
-                cause =
-                    cause.derived_host_cause(parent_host_pred, |derived| {
-                        ObligationCauseCode::ImplDerivedHost(Box::new(
-                            traits::ImplDerivedHostCause { derived, impl_def_id, span },
-                        ))
-                    })
-            }
-        }
-        inspect::ProbeKind::TraitCandidate {
-            source: CandidateSource::BuiltinImpl(..),
-            result: _,
-        } => {
-            cause =
-                cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
-        }
-        _ => {}
-    };
-    cause
-}
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
new file mode 100644
index 00000000000..c64bc19835b
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -0,0 +1,527 @@
+use std::ops::ControlFlow;
+
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
+use rustc_infer::traits::{
+    self, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
+    PredicateObligation, SelectionError,
+};
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::{bug, span_bug};
+use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _};
+use rustc_type_ir::solve::{Goal, NoSolution};
+use tracing::{instrument, trace};
+
+use crate::solve::Certainty;
+use crate::solve::delegate::SolverDelegate;
+use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
+use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
+
+pub(super) fn fulfillment_error_for_no_solution<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    root_obligation: PredicateObligation<'tcx>,
+) -> FulfillmentError<'tcx> {
+    let obligation = find_best_leaf_obligation(infcx, &root_obligation, false);
+
+    let code = match obligation.predicate.kind().skip_binder() {
+        ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
+            FulfillmentErrorCode::Project(
+                // FIXME: This could be a `Sorts` if the term is a type
+                MismatchedProjectionTypes { err: TypeError::Mismatch },
+            )
+        }
+        ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, expected_ty)) => {
+            let ct_ty = match ct.kind() {
+                ty::ConstKind::Unevaluated(uv) => {
+                    infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
+                }
+                ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env),
+                ty::ConstKind::Value(cv) => cv.ty,
+                kind => span_bug!(
+                    obligation.cause.span,
+                    "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}"
+                ),
+            };
+            FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType {
+                ct,
+                ct_ty,
+                expected_ty,
+            })
+        }
+        ty::PredicateKind::NormalizesTo(..) => {
+            FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
+        }
+        ty::PredicateKind::AliasRelate(_, _, _) => {
+            FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
+        }
+        ty::PredicateKind::Subtype(pred) => {
+            let (a, b) = infcx.enter_forall_and_leak_universe(
+                obligation.predicate.kind().rebind((pred.a, pred.b)),
+            );
+            let expected_found = ExpectedFound::new(a, b);
+            FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
+        }
+        ty::PredicateKind::Coerce(pred) => {
+            let (a, b) = infcx.enter_forall_and_leak_universe(
+                obligation.predicate.kind().rebind((pred.a, pred.b)),
+            );
+            let expected_found = ExpectedFound::new(b, a);
+            FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
+        }
+        ty::PredicateKind::Clause(_)
+        | ty::PredicateKind::DynCompatible(_)
+        | ty::PredicateKind::Ambiguous => {
+            FulfillmentErrorCode::Select(SelectionError::Unimplemented)
+        }
+        ty::PredicateKind::ConstEquate(..) => {
+            bug!("unexpected goal: {obligation:?}")
+        }
+    };
+
+    FulfillmentError { obligation, code, root_obligation }
+}
+
+pub(super) fn fulfillment_error_for_stalled<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    root_obligation: PredicateObligation<'tcx>,
+) -> FulfillmentError<'tcx> {
+    let (code, refine_obligation) = infcx.probe(|_| {
+        match <&SolverDelegate<'tcx>>::from(infcx)
+            .evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No)
+            .0
+        {
+            Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
+                (FulfillmentErrorCode::Ambiguity { overflow: None }, true)
+            }
+            Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => (
+                FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
+                // Don't look into overflows because we treat overflows weirdly anyways.
+                // We discard the inference constraints from overflowing goals, so
+                // recomputing the goal again during `find_best_leaf_obligation` may apply
+                // inference guidance that makes other goals go from ambig -> pass, for example.
+                //
+                // FIXME: We should probably just look into overflows here.
+                false,
+            ),
+            Ok((_, Certainty::Yes)) => {
+                bug!("did not expect successful goal when collecting ambiguity errors")
+            }
+            Err(_) => {
+                bug!("did not expect selection error when collecting ambiguity errors")
+            }
+        }
+    });
+
+    FulfillmentError {
+        obligation: if refine_obligation {
+            find_best_leaf_obligation(infcx, &root_obligation, true)
+        } else {
+            root_obligation.clone()
+        },
+        code,
+        root_obligation,
+    }
+}
+
+pub(super) fn fulfillment_error_for_overflow<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    root_obligation: PredicateObligation<'tcx>,
+) -> FulfillmentError<'tcx> {
+    FulfillmentError {
+        obligation: find_best_leaf_obligation(infcx, &root_obligation, true),
+        code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
+        root_obligation,
+    }
+}
+
+fn find_best_leaf_obligation<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    obligation: &PredicateObligation<'tcx>,
+    consider_ambiguities: bool,
+) -> PredicateObligation<'tcx> {
+    let obligation = infcx.resolve_vars_if_possible(obligation.clone());
+    // FIXME: we use a probe here as the `BestObligation` visitor does not
+    // check whether it uses candidates which get shadowed by where-bounds.
+    //
+    // We should probably fix the visitor to not do so instead, as this also
+    // means the leaf obligation may be incorrect.
+    infcx
+        .fudge_inference_if_ok(|| {
+            infcx
+                .visit_proof_tree(obligation.clone().into(), &mut BestObligation {
+                    obligation: obligation.clone(),
+                    consider_ambiguities,
+                })
+                .break_value()
+                .ok_or(())
+        })
+        .unwrap_or(obligation)
+}
+
+struct BestObligation<'tcx> {
+    obligation: PredicateObligation<'tcx>,
+    consider_ambiguities: bool,
+}
+
+impl<'tcx> BestObligation<'tcx> {
+    fn with_derived_obligation(
+        &mut self,
+        derived_obligation: PredicateObligation<'tcx>,
+        and_then: impl FnOnce(&mut Self) -> <Self as ProofTreeVisitor<'tcx>>::Result,
+    ) -> <Self as ProofTreeVisitor<'tcx>>::Result {
+        let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation);
+        let res = and_then(self);
+        self.obligation = old_obligation;
+        res
+    }
+
+    /// Filter out the candidates that aren't interesting to visit for the
+    /// purposes of reporting errors. For ambiguities, we only consider
+    /// candidates that may hold. For errors, we only consider candidates that
+    /// *don't* hold and which have impl-where clauses that also don't hold.
+    fn non_trivial_candidates<'a>(
+        &self,
+        goal: &'a inspect::InspectGoal<'a, 'tcx>,
+    ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> {
+        let mut candidates = goal.candidates();
+        match self.consider_ambiguities {
+            true => {
+                // If we have an ambiguous obligation, we must consider *all* candidates
+                // that hold, or else we may guide inference causing other goals to go
+                // from ambig -> pass/fail.
+                candidates.retain(|candidate| candidate.result().is_ok());
+            }
+            false => {
+                // If we have >1 candidate, one may still be due to "boring" reasons, like
+                // an alias-relate that failed to hold when deeply evaluated. We really
+                // don't care about reasons like this.
+                if candidates.len() > 1 {
+                    candidates.retain(|candidate| {
+                        goal.infcx().probe(|_| {
+                            candidate.instantiate_nested_goals(self.span()).iter().any(
+                                |nested_goal| {
+                                    matches!(
+                                        nested_goal.source(),
+                                        GoalSource::ImplWhereBound
+                                            | GoalSource::AliasBoundConstCondition
+                                            | GoalSource::InstantiateHigherRanked
+                                            | GoalSource::AliasWellFormed
+                                    ) && match (self.consider_ambiguities, nested_goal.result()) {
+                                        (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity)))
+                                        | (false, Err(_)) => true,
+                                        _ => false,
+                                    }
+                                },
+                            )
+                        })
+                    });
+                }
+
+                // Prefer a non-rigid candidate if there is one.
+                if candidates.len() > 1 {
+                    candidates.retain(|candidate| {
+                        !matches!(candidate.kind(), inspect::ProbeKind::RigidAlias { .. })
+                    });
+                }
+            }
+        }
+
+        candidates
+    }
+
+    /// HACK: We walk the nested obligations for a well-formed arg manually,
+    /// since there's nontrivial logic in `wf.rs` to set up an obligation cause.
+    /// Ideally we'd be able to track this better.
+    fn visit_well_formed_goal(
+        &mut self,
+        candidate: &inspect::InspectCandidate<'_, 'tcx>,
+        arg: ty::GenericArg<'tcx>,
+    ) -> ControlFlow<PredicateObligation<'tcx>> {
+        let infcx = candidate.goal().infcx();
+        let param_env = candidate.goal().goal().param_env;
+        let body_id = self.obligation.cause.body_id;
+
+        for obligation in wf::unnormalized_obligations(infcx, param_env, arg, self.span(), body_id)
+            .into_iter()
+            .flatten()
+        {
+            let nested_goal = candidate.instantiate_proof_tree_for_nested_goal(
+                GoalSource::Misc,
+                Goal::new(infcx.tcx, obligation.param_env, obligation.predicate),
+                self.span(),
+            );
+            // Skip nested goals that aren't the *reason* for our goal's failure.
+            match (self.consider_ambiguities, nested_goal.result()) {
+                (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {}
+                _ => continue,
+            }
+
+            self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
+        }
+
+        ControlFlow::Break(self.obligation.clone())
+    }
+}
+
+impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
+    type Result = ControlFlow<PredicateObligation<'tcx>>;
+
+    fn span(&self) -> rustc_span::Span {
+        self.obligation.cause.span
+    }
+
+    #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
+    fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
+        let candidates = self.non_trivial_candidates(goal);
+        trace!(candidates = ?candidates.iter().map(|c| c.kind()).collect::<Vec<_>>());
+
+        let [candidate] = candidates.as_slice() else {
+            return ControlFlow::Break(self.obligation.clone());
+        };
+
+        // Don't walk into impls that have `do_not_recommend`.
+        if let inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::Impl(impl_def_id),
+            result: _,
+        } = candidate.kind()
+            && goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
+        {
+            return ControlFlow::Break(self.obligation.clone());
+        }
+
+        let tcx = goal.infcx().tcx;
+        // FIXME: Also, what about considering >1 layer up the stack? May be necessary
+        // for normalizes-to.
+        let pred_kind = goal.goal().predicate.kind();
+        let child_mode = match pred_kind.skip_binder() {
+            ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
+                ChildMode::Trait(pred_kind.rebind(pred))
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => {
+                ChildMode::Host(pred_kind.rebind(pred))
+            }
+            ty::PredicateKind::NormalizesTo(normalizes_to)
+                if matches!(
+                    normalizes_to.alias.kind(tcx),
+                    ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst
+                ) =>
+            {
+                ChildMode::Trait(pred_kind.rebind(ty::TraitPredicate {
+                    trait_ref: normalizes_to.alias.trait_ref(tcx),
+                    polarity: ty::PredicatePolarity::Positive,
+                }))
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+                return self.visit_well_formed_goal(candidate, arg);
+            }
+            _ => ChildMode::PassThrough,
+        };
+
+        let nested_goals = candidate.instantiate_nested_goals(self.span());
+
+        // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as
+        // an actual candidate, instead we should treat them as if the impl was never considered to
+        // have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written
+        // instead of `impl<T: FnPtr> Trait for T`.
+        //
+        // We do this as a separate loop so that we do not choose to tell the user about some nested
+        // goal before we encounter a `T: FnPtr` nested goal.
+        for nested_goal in &nested_goals {
+            if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait()
+                && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
+                && poly_trait_pred.def_id() == fn_ptr_trait
+                && let Err(NoSolution) = nested_goal.result()
+            {
+                return ControlFlow::Break(self.obligation.clone());
+            }
+        }
+
+        let mut impl_where_bound_count = 0;
+        for nested_goal in nested_goals {
+            trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
+
+            let make_obligation = |cause| Obligation {
+                cause,
+                param_env: nested_goal.goal().param_env,
+                predicate: nested_goal.goal().predicate,
+                recursion_depth: self.obligation.recursion_depth + 1,
+            };
+
+            let obligation;
+            match (child_mode, nested_goal.source()) {
+                (ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => {
+                    continue;
+                }
+                (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
+                    obligation = make_obligation(derive_cause(
+                        tcx,
+                        candidate.kind(),
+                        self.obligation.cause.clone(),
+                        impl_where_bound_count,
+                        parent_trait_pred,
+                    ));
+                    impl_where_bound_count += 1;
+                }
+                (
+                    ChildMode::Host(parent_host_pred),
+                    GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
+                ) => {
+                    obligation = make_obligation(derive_host_cause(
+                        tcx,
+                        candidate.kind(),
+                        self.obligation.cause.clone(),
+                        impl_where_bound_count,
+                        parent_host_pred,
+                    ));
+                    impl_where_bound_count += 1;
+                }
+                // Skip over a higher-ranked predicate.
+                (_, GoalSource::InstantiateHigherRanked) => {
+                    obligation = self.obligation.clone();
+                }
+                (ChildMode::PassThrough, _)
+                | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
+                    obligation = make_obligation(self.obligation.cause.clone());
+                }
+            }
+
+            // Skip nested goals that aren't the *reason* for our goal's failure.
+            match (self.consider_ambiguities, nested_goal.result()) {
+                (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {}
+                _ => continue,
+            }
+
+            self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
+        }
+
+        // alias-relate may fail because the lhs or rhs can't be normalized,
+        // and therefore is treated as rigid.
+        if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred_kind.no_bound_vars() {
+            if let Some(obligation) = goal
+                .infcx()
+                .visit_proof_tree_at_depth(
+                    goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())),
+                    goal.depth() + 1,
+                    self,
+                )
+                .break_value()
+            {
+                return ControlFlow::Break(obligation);
+            } else if let Some(obligation) = goal
+                .infcx()
+                .visit_proof_tree_at_depth(
+                    goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())),
+                    goal.depth() + 1,
+                    self,
+                )
+                .break_value()
+            {
+                return ControlFlow::Break(obligation);
+            }
+        }
+
+        ControlFlow::Break(self.obligation.clone())
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+enum ChildMode<'tcx> {
+    // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
+    // and skip all `GoalSource::Misc`, which represent useless obligations
+    // such as alias-eq which may not hold.
+    Trait(ty::PolyTraitPredicate<'tcx>),
+    // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
+    // and skip all `GoalSource::Misc`, which represent useless obligations
+    // such as alias-eq which may not hold.
+    Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
+    // Skip trying to derive an `ObligationCause` from this obligation, and
+    // report *all* sub-obligations as if they came directly from the parent
+    // obligation.
+    PassThrough,
+}
+
+fn derive_cause<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
+    mut cause: ObligationCause<'tcx>,
+    idx: usize,
+    parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+) -> ObligationCause<'tcx> {
+    match candidate_kind {
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::Impl(impl_def_id),
+            result: _,
+        } => {
+            if let Some((_, span)) =
+                tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
+            {
+                cause = cause.derived_cause(parent_trait_pred, |derived| {
+                    ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
+                        derived,
+                        impl_or_alias_def_id: impl_def_id,
+                        impl_def_predicate_index: Some(idx),
+                        span,
+                    }))
+                })
+            }
+        }
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::BuiltinImpl(..),
+            result: _,
+        } => {
+            cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived);
+        }
+        _ => {}
+    };
+    cause
+}
+
+fn derive_host_cause<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
+    mut cause: ObligationCause<'tcx>,
+    idx: usize,
+    parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
+) -> ObligationCause<'tcx> {
+    match candidate_kind {
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::Impl(impl_def_id),
+            result: _,
+        } => {
+            if let Some((_, span)) = tcx
+                .predicates_of(impl_def_id)
+                .instantiate_identity(tcx)
+                .into_iter()
+                .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
+                    |(trait_ref, span)| {
+                        (
+                            trait_ref.to_host_effect_clause(
+                                tcx,
+                                parent_host_pred.skip_binder().constness,
+                            ),
+                            span,
+                        )
+                    },
+                ))
+                .nth(idx)
+            {
+                cause =
+                    cause.derived_host_cause(parent_host_pred, |derived| {
+                        ObligationCauseCode::ImplDerivedHost(Box::new(
+                            traits::ImplDerivedHostCause { derived, impl_def_id, span },
+                        ))
+                    })
+            }
+        }
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::BuiltinImpl(..),
+            result: _,
+        } => {
+            cause =
+                cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
+        }
+        _ => {}
+    };
+    cause
+}
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index e735020a63e..9ba48cd588f 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -194,47 +194,57 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
 
         let goals = instantiated_goals
             .into_iter()
-            .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() {
-                Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
-                    let unconstrained_term = match term.unpack() {
-                        ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(),
-                        ty::TermKind::Const(_) => infcx.next_const_var(span).into(),
-                    };
-                    let goal =
-                        goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
-                    // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
-                    // expected term. This means that candidates which only fail due to nested goals
-                    // and which normalize to a different term then the final result could ICE: when
-                    // building their proof tree, the expected term was unconstrained, but when
-                    // instantiating the candidate it is already constrained to the result of another
-                    // candidate.
-                    let proof_tree = infcx
-                        .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1);
-                    InspectGoal::new(
-                        infcx,
-                        self.goal.depth + 1,
-                        proof_tree.unwrap(),
-                        Some(NormalizesToTermHack { term, unconstrained_term }),
-                        source,
-                    )
-                }
-                _ => {
-                    // We're using a probe here as evaluating a goal could constrain
-                    // inference variables by choosing one candidate. If we then recurse
-                    // into another candidate who ends up with different inference
-                    // constraints, we get an ICE if we already applied the constraints
-                    // from the chosen candidate.
-                    let proof_tree = infcx
-                        .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
-                        .unwrap();
-                    InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
-                }
-            })
+            .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span))
             .collect();
 
         (goals, opt_impl_args)
     }
 
+    pub fn instantiate_proof_tree_for_nested_goal(
+        &self,
+        source: GoalSource,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+        span: Span,
+    ) -> InspectGoal<'a, 'tcx> {
+        let infcx = self.goal.infcx;
+        match goal.predicate.kind().no_bound_vars() {
+            Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
+                let unconstrained_term = match term.unpack() {
+                    ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(),
+                    ty::TermKind::Const(_) => infcx.next_const_var(span).into(),
+                };
+                let goal =
+                    goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
+                // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
+                // expected term. This means that candidates which only fail due to nested goals
+                // and which normalize to a different term then the final result could ICE: when
+                // building their proof tree, the expected term was unconstrained, but when
+                // instantiating the candidate it is already constrained to the result of another
+                // candidate.
+                let proof_tree =
+                    infcx.probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1);
+                InspectGoal::new(
+                    infcx,
+                    self.goal.depth + 1,
+                    proof_tree.unwrap(),
+                    Some(NormalizesToTermHack { term, unconstrained_term }),
+                    source,
+                )
+            }
+            _ => {
+                // We're using a probe here as evaluating a goal could constrain
+                // inference variables by choosing one candidate. If we then recurse
+                // into another candidate who ends up with different inference
+                // constraints, we get an ICE if we already applied the constraints
+                // from the chosen candidate.
+                let proof_tree = infcx
+                    .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
+                    .unwrap();
+                InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
+            }
+        }
+    }
+
     /// Visit all nested goals of this candidate, rolling back
     /// all inference constraints.
     pub fn visit_nested_in_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 9a53e8a5d51..1fca2f4da7e 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -6,6 +6,7 @@ use std::iter;
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_data_structures::unord::UnordSet;
+use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::ty::{Region, RegionVid};
 use tracing::debug;
@@ -13,6 +14,7 @@ use tracing::debug;
 use super::*;
 use crate::errors::UnableToConstructConstantValue;
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
+use crate::regions::OutlivesEnvironmentBuildExt;
 use crate::traits::project::ProjectAndUnifyResult;
 
 // FIXME(twk): this is obviously not nice to duplicate like that
@@ -158,7 +160,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             panic!("Unable to fulfill trait {trait_did:?} for '{ty:?}': {errors:?}");
         }
 
-        let outlives_env = OutlivesEnvironment::new(full_env);
+        let outlives_env = OutlivesEnvironment::new(&infcx, CRATE_DEF_ID, full_env, []);
         let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty));
 
         let region_data = infcx.inner.borrow_mut().unwrap_region_constraints().data().clone();
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 50d47d20e1a..7ee9eb45309 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -9,7 +9,7 @@ use std::fmt::Debug;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::{Diag, EmissionGuarantee};
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::PredicateObligations;
 use rustc_middle::bug;
@@ -27,7 +27,6 @@ use tracing::{debug, instrument, warn};
 use super::ObligationCtxt;
 use crate::error_reporting::traits::suggest_new_overflow_limit;
 use crate::infer::InferOk;
-use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
 use crate::solve::{SolverDelegate, deeply_normalize_for_diagnostics, inspect};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -596,8 +595,7 @@ fn try_prove_negated_where_clause<'tcx>(
     // FIXME: We could use the assumed_wf_types from both impls, I think,
     // if that wasn't implemented just for LocalDefId, and we'd need to do
     // the normalization ourselves since this is totally fallible...
-    let outlives_env = OutlivesEnvironment::new(param_env);
-    let errors = ocx.resolve_regions(&outlives_env);
+    let errors = ocx.resolve_regions(CRATE_DEF_ID, param_env, []);
     if !errors.is_empty() {
         return false;
     }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 446f9eaa348..bdee6ca2afe 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -35,7 +35,7 @@ pub fn is_const_evaluatable<'tcx>(
         ty::ConstKind::Param(_)
         | ty::ConstKind::Bound(_, _)
         | ty::ConstKind::Placeholder(_)
-        | ty::ConstKind::Value(_, _)
+        | ty::ConstKind::Value(_)
         | ty::ConstKind::Error(_) => return Ok(()),
         ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
     };
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index 66491d9abe1..baa94ead9d4 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -64,7 +64,7 @@ fn is_dyn_compatible(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
 }
 
 /// We say a method is *vtable safe* if it can be invoked on a trait
-/// object. Note that object-safe traits can have some
+/// object. Note that dyn-compatible traits can have some
 /// non-vtable-safe methods, so long as they require `Self: Sized` or
 /// otherwise ensure that they cannot be used when `Self = Trait`.
 pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
@@ -421,7 +421,7 @@ fn virtual_call_violations_for_method<'tcx>(
     let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
 
     // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
-    // However, this is already considered object-safe. We allow it as a special case here.
+    // However, this is already considered dyn compatible. We allow it as a special case here.
     // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
     // `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
     if receiver_ty != tcx.types.self_param {
@@ -631,7 +631,7 @@ fn object_ty_for_trait<'tcx>(
 /// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
 ///
 /// The only case where the receiver is not dispatchable, but is still a valid receiver
-/// type (just not object-safe), is when there is more than one level of pointer indirection.
+/// type (just not dyn compatible), is when there is more than one level of pointer indirection.
 /// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
 /// is no way, or at least no inexpensive way, to coerce the receiver from the version where
 /// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 4a3983fca31..9f3178f8879 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -8,7 +8,6 @@ use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
 };
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace};
 use rustc_infer::traits::PredicateObligations;
 use rustc_macros::extension;
@@ -217,14 +216,15 @@ where
     /// will result in region constraints getting ignored.
     pub fn resolve_regions_and_report_errors(
         self,
-        generic_param_scope: LocalDefId,
-        outlives_env: &OutlivesEnvironment<'tcx>,
+        body_id: LocalDefId,
+        param_env: ty::ParamEnv<'tcx>,
+        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
     ) -> Result<(), ErrorGuaranteed> {
-        let errors = self.infcx.resolve_regions(outlives_env);
+        let errors = self.infcx.resolve_regions(body_id, param_env, assumed_wf_tys);
         if errors.is_empty() {
             Ok(())
         } else {
-            Err(self.infcx.err_ctxt().report_region_errors(generic_param_scope, &errors))
+            Err(self.infcx.err_ctxt().report_region_errors(body_id, &errors))
         }
     }
 
@@ -235,9 +235,11 @@ where
     #[must_use]
     pub fn resolve_regions(
         self,
-        outlives_env: &OutlivesEnvironment<'tcx>,
+        body_id: LocalDefId,
+        param_env: ty::ParamEnv<'tcx>,
+        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
     ) -> Vec<RegionResolutionError<'tcx>> {
-        self.infcx.resolve_regions(outlives_env)
+        self.infcx.resolve_regions(body_id, param_env, assumed_wf_tys)
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 7529ee128f5..f2d2dd2f3ce 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -479,7 +479,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         ty::ConstKind::Error(_) => {
                             return ProcessResult::Changed(PendingPredicateObligations::new());
                         }
-                        ty::ConstKind::Value(ty, _) => ty,
+                        ty::ConstKind::Value(cv) => cv.ty,
                         ty::ConstKind::Unevaluated(uv) => {
                             infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 7a67b943e94..79e178150de 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -4,13 +4,10 @@ use std::assert_matches::assert_matches;
 
 use hir::LangItem;
 use rustc_ast::Mutability;
-use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 
-use super::outlives_bounds::InferCtxtExt;
 use crate::regions::InferCtxtRegionExt;
 use crate::traits::{self, FulfillmentError, ObligationCause};
 
@@ -170,15 +167,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
         }
 
         // Check regions assuming the self type of the impl is WF
-        let outlives_env = OutlivesEnvironment::with_bounds(
-            param_env,
-            infcx.implied_bounds_tys(
-                param_env,
-                parent_cause.body_id,
-                &FxIndexSet::from_iter([self_type]),
-            ),
-        );
-        let errors = infcx.resolve_regions(&outlives_env);
+        let errors = infcx.resolve_regions(parent_cause.body_id, param_env, [self_type]);
         if !errors.is_empty() {
             infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Regions(errors)));
             continue;
@@ -261,15 +250,7 @@ pub fn all_fields_implement_trait<'tcx>(
             }
 
             // Check regions assuming the self type of the impl is WF
-            let outlives_env = OutlivesEnvironment::with_bounds(
-                param_env,
-                infcx.implied_bounds_tys(
-                    param_env,
-                    parent_cause.body_id,
-                    &FxIndexSet::from_iter([self_type]),
-                ),
-            );
-            let errors = infcx.resolve_regions(&outlives_env);
+            let errors = infcx.resolve_regions(parent_cause.body_id, param_env, [self_type]);
             if !errors.is_empty() {
                 infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
             }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index fe5ad003a7e..d4a9664e282 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -76,6 +76,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::regions::InferCtxtRegionExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 
+#[derive(Debug)]
 pub struct FulfillmentError<'tcx> {
     pub obligation: PredicateObligation<'tcx>,
     pub code: FulfillmentErrorCode<'tcx>,
@@ -107,12 +108,6 @@ impl<'tcx> FulfillmentError<'tcx> {
     }
 }
 
-impl<'tcx> Debug for FulfillmentError<'tcx> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code)
-    }
-}
-
 #[derive(Clone)]
 pub enum FulfillmentErrorCode<'tcx> {
     /// Inherently impossible to fulfill; this trait is implemented if and only
@@ -290,12 +285,10 @@ fn do_normalize_predicates<'tcx>(
 
     // We can use the `elaborated_env` here; the region code only
     // cares about declarations like `'a: 'b`.
-    let outlives_env = OutlivesEnvironment::new(elaborated_env);
-
     // FIXME: It's very weird that we ignore region obligations but apparently
     // still need to use `resolve_regions` as we need the resolved regions in
     // the normalized predicates.
-    let errors = infcx.resolve_regions(&outlives_env);
+    let errors = infcx.resolve_regions(cause.body_id, elaborated_env, []);
     if !errors.is_empty() {
         tcx.dcx().span_delayed_bug(
             span,
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 23dabe32ff2..18932695807 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -1,4 +1,3 @@
-use rustc_data_structures::fx::FxIndexSet;
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
@@ -12,9 +11,6 @@ use tracing::instrument;
 use crate::infer::InferCtxt;
 use crate::traits::{ObligationCause, ObligationCtxt};
 
-pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
-pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
-
 /// Implied bounds are region relationships that we deduce
 /// automatically. The idea is that (e.g.) a caller must check that a
 /// function's argument types are well-formed immediately before
@@ -110,36 +106,18 @@ fn implied_outlives_bounds<'a, 'tcx>(
     bounds
 }
 
-#[extension(pub trait InferCtxtExt<'a, 'tcx>)]
-impl<'a, 'tcx: 'a> InferCtxt<'tcx> {
-    /// Do *NOT* call this directly.
-    fn implied_bounds_tys_compat(
-        &'a self,
-        param_env: ParamEnv<'tcx>,
+#[extension(pub trait InferCtxtExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
+    /// Do *NOT* call this directly. You probably want to construct a `OutlivesEnvironment`
+    /// instead if you're interested in the implied bounds for a given signature.
+    fn implied_bounds_tys_with_compat<Tys: IntoIterator<Item = Ty<'tcx>>>(
+        &self,
         body_id: LocalDefId,
-        tys: &'a FxIndexSet<Ty<'tcx>>,
-        compat: bool,
-    ) -> BoundsCompat<'a, 'tcx> {
-        tys.iter()
-            .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, compat))
-    }
-
-    /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat`
-    /// with `compat` set to `true`, otherwise `false`.
-    fn implied_bounds_tys(
-        &'a self,
         param_env: ParamEnv<'tcx>,
-        body_id: LocalDefId,
-        tys: &'a FxIndexSet<Ty<'tcx>>,
-    ) -> Bounds<'a, 'tcx> {
-        tys.iter().flat_map(move |ty| {
-            implied_outlives_bounds(
-                self,
-                param_env,
-                body_id,
-                *ty,
-                !self.tcx.sess.opts.unstable_opts.no_implied_bounds_compat,
-            )
-        })
+        tys: Tys,
+        compat: bool,
+    ) -> impl Iterator<Item = OutlivesBound<'tcx>> {
+        tys.into_iter()
+            .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, ty, compat))
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 1339739ce7f..ec0b7903396 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -5,8 +5,8 @@ use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
 use rustc_middle::infer::canonical::CanonicalQueryResponse;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
-use rustc_span::Span;
 use rustc_span::def_id::CRATE_DEF_ID;
+use rustc_span::{DUMMY_SP, Span};
 use rustc_type_ir::outlives::{Component, push_outlives_components};
 use smallvec::{SmallVec, smallvec};
 use tracing::debug;
@@ -92,7 +92,9 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
 
         // From the full set of obligations, just filter down to the region relationships.
         for obligation in
-            wf::unnormalized_obligations(ocx.infcx, param_env, arg).into_iter().flatten()
+            wf::unnormalized_obligations(ocx.infcx, param_env, arg, DUMMY_SP, CRATE_DEF_ID)
+                .into_iter()
+                .flatten()
         {
             assert!(!obligation.has_escaping_bound_vars());
             let Some(pred) = obligation.predicate.kind().no_bound_vars() else {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 6b6e0b32385..99ce1fd9fb4 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -962,7 +962,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             return Ok(EvaluatedToAmbig);
                         }
                         ty::ConstKind::Error(_) => return Ok(EvaluatedToOk),
-                        ty::ConstKind::Value(ty, _) => ty,
+                        ty::ConstKind::Value(cv) => cv.ty,
                         ty::ConstKind::Unevaluated(uv) => {
                             self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args)
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 401b41c796d..cb3e81f5477 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -575,7 +575,7 @@ fn report_conflicting_impls<'tcx>(
     match used_to_be_allowed {
         None => {
             let reported = if overlap.with_impl.is_local()
-                || tcx.ensure().orphan_check_impl(impl_def_id).is_ok()
+                || tcx.ensure_ok().orphan_check_impl(impl_def_id).is_ok()
             {
                 let mut err = tcx.dcx().struct_span_err(impl_span, msg());
                 err.code(E0119);
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 c351cf5aaac..f39c611d19f 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -379,7 +379,7 @@ pub(crate) fn assoc_def(
         // Ensure that the impl is constrained, otherwise projection may give us
         // bad unconstrained infer vars.
         if let Some(impl_def_id) = impl_def_id.as_local() {
-            tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
+            tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
         }
 
         let item = tcx.associated_item(impl_item_id);
@@ -402,7 +402,7 @@ pub(crate) fn assoc_def(
         if assoc_item.item.container == ty::AssocItemContainer::Impl
             && let Some(impl_def_id) = assoc_item.item.container_id(tcx).as_local()
         {
-            tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
+            tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
         }
 
         Ok(assoc_item)
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index c9fb2a757e1..d30363ec158 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -25,7 +25,7 @@ use tracing::debug;
 /// trait Bar {}
 /// trait Foo = Bar + Bar;
 ///
-/// let not_object_safe: dyn Foo; // bad, two `Bar` principals.
+/// let dyn_incompatible: dyn Foo; // bad, two `Bar` principals.
 /// ```
 pub fn expand_trait_aliases<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index b5bc8364c7b..000e6a765d3 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -2,26 +2,22 @@ use std::fmt::Debug;
 use std::ops::ControlFlow;
 
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::at::ToTrace;
-use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt};
-use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::util::PredicateSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
     self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry,
 };
-use rustc_span::{DUMMY_SP, Span, sym};
+use rustc_span::DUMMY_SP;
 use smallvec::{SmallVec, smallvec};
 use tracing::debug;
 
-use crate::errors::DumpVTableEntries;
-use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method};
+use crate::traits::{impossible_predicates, is_vtable_safe_method};
 
 #[derive(Clone, Debug)]
 pub enum VtblSegment<'tcx> {
     MetadataDSA,
-    TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool },
+    TraitOwnEntries { trait_ref: ty::TraitRef<'tcx>, emit_vptr: bool },
 }
 
 /// Prepare the segments for a vtable
@@ -29,7 +25,7 @@ pub enum VtblSegment<'tcx> {
 // about our `Self` type here.
 pub fn prepare_vtable_segments<'tcx, T>(
     tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
+    trait_ref: ty::TraitRef<'tcx>,
     segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
 ) -> Option<T> {
     prepare_vtable_segments_inner(tcx, trait_ref, segment_visitor).break_value()
@@ -39,7 +35,7 @@ pub fn prepare_vtable_segments<'tcx, T>(
 /// such that we can use `?` in the body.
 fn prepare_vtable_segments_inner<'tcx, T>(
     tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
+    trait_ref: ty::TraitRef<'tcx>,
     mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
 ) -> ControlFlow<T> {
     // The following constraints holds for the final arrangement.
@@ -92,7 +88,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
     let mut emit_vptr_on_new_entry = false;
     let mut visited = PredicateSet::new(tcx);
     let predicate = trait_ref.upcast(tcx);
-    let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
+    let mut stack: SmallVec<[(ty::TraitRef<'tcx>, _, _); 5]> =
         smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))];
     visited.insert(predicate);
 
@@ -125,10 +121,18 @@ fn prepare_vtable_segments_inner<'tcx, T>(
             let &(inner_most_trait_ref, _, _) = stack.last().unwrap();
 
             let mut direct_super_traits_iter = tcx
-                .explicit_super_predicates_of(inner_most_trait_ref.def_id())
+                .explicit_super_predicates_of(inner_most_trait_ref.def_id)
                 .iter_identity_copied()
                 .filter_map(move |(pred, _)| {
-                    pred.instantiate_supertrait(tcx, inner_most_trait_ref).as_trait_clause()
+                    pred.instantiate_supertrait(tcx, ty::Binder::dummy(inner_most_trait_ref))
+                        .as_trait_clause()
+                })
+                .map(move |pred| {
+                    tcx.normalize_erasing_late_bound_regions(
+                        ty::TypingEnv::fully_monomorphized(),
+                        pred,
+                    )
+                    .trait_ref
                 });
 
             // Find an unvisited supertrait
@@ -136,16 +140,11 @@ fn prepare_vtable_segments_inner<'tcx, T>(
                 .find(|&super_trait| visited.insert(super_trait.upcast(tcx)))
             {
                 // Push it to the stack for the next iteration of 'diving_in to pick up
-                Some(unvisited_super_trait) => {
-                    // We're throwing away potential constness of super traits here.
-                    // FIXME: handle ~const super traits
-                    let next_super_trait = unvisited_super_trait.map_bound(|t| t.trait_ref);
-                    stack.push((
-                        next_super_trait,
-                        emit_vptr_on_new_entry,
-                        maybe_iter(Some(direct_super_traits_iter)),
-                    ))
-                }
+                Some(next_super_trait) => stack.push((
+                    next_super_trait,
+                    emit_vptr_on_new_entry,
+                    maybe_iter(Some(direct_super_traits_iter)),
+                )),
 
                 // There are no more unvisited direct super traits, dive-in finished
                 None => break 'diving_in,
@@ -154,8 +153,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
 
         // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
         while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() {
-            let has_entries =
-                has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id());
+            let has_entries = has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id);
 
             segment_visitor(VtblSegment::TraitOwnEntries {
                 trait_ref: inner_most_trait_ref,
@@ -169,11 +167,6 @@ fn prepare_vtable_segments_inner<'tcx, T>(
             if let Some(next_inner_most_trait_ref) =
                 siblings.find(|&sibling| visited.insert(sibling.upcast(tcx)))
             {
-                // We're throwing away potential constness of super traits here.
-                // FIXME: handle ~const super traits
-                let next_inner_most_trait_ref =
-                    next_inner_most_trait_ref.map_bound(|t| t.trait_ref);
-
                 stack.push((next_inner_most_trait_ref, emit_vptr_on_new_entry, siblings));
 
                 // just pushed a new trait onto the stack, so we need to go through its super traits
@@ -192,15 +185,6 @@ fn maybe_iter<I: Iterator>(i: Option<I>) -> impl Iterator<Item = I::Item> {
     i.into_iter().flatten()
 }
 
-fn dump_vtable_entries<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    sp: Span,
-    trait_ref: ty::PolyTraitRef<'tcx>,
-    entries: &[VtblEntry<'tcx>],
-) {
-    tcx.dcx().emit_err(DumpVTableEntries { span: sp, trait_ref, entries: format!("{entries:#?}") });
-}
-
 fn has_own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
     own_existential_vtable_entries_iter(tcx, trait_def_id).next().is_some()
 }
@@ -239,8 +223,15 @@ fn own_existential_vtable_entries_iter(
 /// that come from `trait_ref`, including its supertraits.
 fn vtable_entries<'tcx>(
     tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
+    trait_ref: ty::TraitRef<'tcx>,
 ) -> &'tcx [VtblEntry<'tcx>] {
+    debug_assert!(!trait_ref.has_non_region_infer() && !trait_ref.has_non_region_param());
+    debug_assert_eq!(
+        tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref),
+        trait_ref,
+        "vtable trait ref should be normalized"
+    );
+
     debug!("vtable_entries({:?})", trait_ref);
 
     let mut entries = vec![];
@@ -251,33 +242,26 @@ fn vtable_entries<'tcx>(
                 entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES);
             }
             VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                let existential_trait_ref = trait_ref
-                    .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+                let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref);
 
                 // Lookup the shape of vtable for the trait.
                 let own_existential_entries =
-                    tcx.own_existential_vtable_entries(existential_trait_ref.def_id());
+                    tcx.own_existential_vtable_entries(existential_trait_ref.def_id);
 
                 let own_entries = own_existential_entries.iter().copied().map(|def_id| {
                     debug!("vtable_entries: trait_method={:?}", def_id);
 
                     // The method may have some early-bound lifetimes; add regions for those.
-                    let args = trait_ref.map_bound(|trait_ref| {
+                    // FIXME: Is this normalize needed?
+                    let args = tcx.normalize_erasing_regions(
+                        ty::TypingEnv::fully_monomorphized(),
                         GenericArgs::for_item(tcx, def_id, |param, _| match param.kind {
                             GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
                             GenericParamDefKind::Type { .. }
                             | GenericParamDefKind::Const { .. } => {
                                 trait_ref.args[param.index as usize]
                             }
-                        })
-                    });
-
-                    // The trait type may have higher-ranked lifetimes in it;
-                    // erase them if they appear, so that we get the type
-                    // at some particular call site.
-                    let args = tcx.normalize_erasing_late_bound_regions(
-                        ty::TypingEnv::fully_monomorphized(),
-                        args,
+                        }),
                     );
 
                     // It's possible that the method relies on where-clauses that
@@ -317,11 +301,6 @@ fn vtable_entries<'tcx>(
 
     let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
 
-    if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) {
-        let sp = tcx.def_span(trait_ref.def_id());
-        dump_vtable_entries(tcx, sp, trait_ref, &entries);
-    }
-
     tcx.arena.alloc_from_iter(entries)
 }
 
@@ -329,14 +308,20 @@ fn vtable_entries<'tcx>(
 // for `Supertrait`'s methods in the vtable of `Subtrait`.
 pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRef<'tcx>) -> usize {
     debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param());
+    debug_assert_eq!(
+        tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), key),
+        key,
+        "vtable trait ref should be normalized"
+    );
 
     let ty::Dynamic(source, _, _) = *key.self_ty().kind() else {
         bug!();
     };
-    let source_principal =
-        source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let source_principal = tcx.instantiate_bound_regions_with_erased(
+        source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self),
+    );
 
-    let target_principal = ty::Binder::dummy(ty::ExistentialTraitRef::erase_self_ty(tcx, key));
+    let target_principal = ty::ExistentialTraitRef::erase_self_ty(tcx, key);
 
     let vtable_segment_callback = {
         let mut vptr_offset = 0;
@@ -346,17 +331,14 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
                     vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                 }
                 VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
-                    if trait_refs_are_compatible(
-                        tcx,
-                        vtable_principal
-                            .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)),
-                        target_principal,
-                    ) {
+                    if ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal)
+                        == target_principal
+                    {
                         return ControlFlow::Break(vptr_offset);
                     }
 
                     vptr_offset +=
-                        tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
+                        tcx.own_existential_vtable_entries(vtable_principal.def_id).len();
 
                     if emit_vptr {
                         vptr_offset += 1;
@@ -382,20 +364,27 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
     ),
 ) -> Option<usize> {
     debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param());
+    debug_assert_eq!(
+        tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), key),
+        key,
+        "upcasting trait refs should be normalized"
+    );
+
     let (source, target) = key;
 
     // If the target principal is `None`, we can just return `None`.
     let ty::Dynamic(target, _, _) = *target.kind() else {
         bug!();
     };
-    let target_principal = target.principal()?;
+    let target_principal = tcx.instantiate_bound_regions_with_erased(target.principal()?);
 
     // Given that we have a target principal, it is a bug for there not to be a source principal.
     let ty::Dynamic(source, _, _) = *source.kind() else {
         bug!();
     };
-    let source_principal =
-        source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
+    let source_principal = tcx.instantiate_bound_regions_with_erased(
+        source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self),
+    );
 
     let vtable_segment_callback = {
         let mut vptr_offset = 0;
@@ -406,13 +395,10 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
                 }
                 VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
                     vptr_offset +=
-                        tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
-                    if trait_refs_are_compatible(
-                        tcx,
-                        vtable_principal
-                            .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)),
-                        target_principal,
-                    ) {
+                        tcx.own_existential_vtable_entries(vtable_principal.def_id).len();
+                    if ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal)
+                        == target_principal
+                    {
                         if emit_vptr {
                             return ControlFlow::Break(Some(vptr_offset));
                         } else {
@@ -432,41 +418,6 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
     prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
 }
 
-fn trait_refs_are_compatible<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>,
-    hr_target_principal: ty::PolyExistentialTraitRef<'tcx>,
-) -> bool {
-    if hr_vtable_principal.def_id() != hr_target_principal.def_id() {
-        return false;
-    }
-
-    let (infcx, param_env) =
-        tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized());
-    let ocx = ObligationCtxt::new(&infcx);
-    let hr_source_principal =
-        ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal);
-    let hr_target_principal =
-        ocx.normalize(&ObligationCause::dummy(), param_env, hr_target_principal);
-    infcx.enter_forall(hr_target_principal, |target_principal| {
-        let source_principal = infcx.instantiate_binder_with_fresh_vars(
-            DUMMY_SP,
-            BoundRegionConversionTime::HigherRankedType,
-            hr_source_principal,
-        );
-        let Ok(()) = ocx.eq_trace(
-            &ObligationCause::dummy(),
-            param_env,
-            ToTrace::to_trace(&ObligationCause::dummy(), hr_target_principal, hr_source_principal),
-            target_principal,
-            source_principal,
-        ) else {
-            return false;
-        };
-        ocx.select_all_or_error().is_empty()
-    })
-}
-
 pub(super) fn provide(providers: &mut Providers) {
     *providers = Providers {
         own_existential_vtable_entries,
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 9d32eb05386..96051ad0aa5 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -8,8 +8,8 @@ use rustc_middle::ty::{
     self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable,
     TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
-use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
-use rustc_span::{DUMMY_SP, Span};
+use rustc_span::Span;
+use rustc_span::def_id::{DefId, LocalDefId};
 use tracing::{debug, instrument, trace};
 
 use crate::infer::InferCtxt;
@@ -89,6 +89,8 @@ pub fn unnormalized_obligations<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     arg: GenericArg<'tcx>,
+    span: Span,
+    body_id: LocalDefId,
 ) -> Option<PredicateObligations<'tcx>> {
     debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
 
@@ -106,8 +108,8 @@ pub fn unnormalized_obligations<'tcx>(
     let mut wf = WfPredicates {
         infcx,
         param_env,
-        body_id: CRATE_DEF_ID,
-        span: DUMMY_SP,
+        body_id,
+        span,
         out: PredicateObligations::new(),
         recursion_depth: 0,
         item: None,
@@ -689,7 +691,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem);
                 // Note that the len being WF is implicitly checked while visiting.
                 // Here we just check that it's of type usize.
-                let cause = self.cause(ObligationCauseCode::Misc);
+                let cause = self.cause(ObligationCauseCode::ArrayLen(t));
                 self.out.push(traits::Obligation::with_depth(
                     tcx,
                     cause,
@@ -828,8 +830,25 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 // Let the visitor iterate into the argument/return
                 // types appearing in the fn signature.
             }
-            ty::UnsafeBinder(_) => {
-                // FIXME(unsafe_binders): We should also recurse into the binder here.
+            ty::UnsafeBinder(ty) => {
+                // FIXME(unsafe_binders): For now, we have no way to express
+                // that a type must be `ManuallyDrop` OR `Copy` (or a pointer).
+                if !ty.has_escaping_bound_vars() {
+                    self.out.push(traits::Obligation::new(
+                        self.tcx(),
+                        self.cause(ObligationCauseCode::Misc),
+                        self.param_env,
+                        ty.map_bound(|ty| {
+                            ty::TraitRef::new(
+                                self.tcx(),
+                                self.tcx().require_lang_item(LangItem::Copy, Some(self.span)),
+                                [ty],
+                            )
+                        }),
+                    ));
+                }
+
+                // We recurse into the binder below.
             }
 
             ty::Dynamic(data, r, _) => {
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index ad86813c87e..a50cc8f5932 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -128,16 +128,16 @@ mod rustc {
         pub fn from_const<'tcx>(
             tcx: TyCtxt<'tcx>,
             param_env: ParamEnv<'tcx>,
-            c: Const<'tcx>,
+            ct: Const<'tcx>,
         ) -> Option<Self> {
             use rustc_middle::ty::ScalarInt;
             use rustc_span::sym;
 
-            let Some((cv, ty)) = c.try_to_valtree() else {
+            let Some(cv) = ct.try_to_value() else {
                 return None;
             };
 
-            let adt_def = ty.ty_adt_def()?;
+            let adt_def = cv.ty.ty_adt_def()?;
 
             assert_eq!(
                 tcx.require_lang_item(LangItem::TransmuteOpts, None),
@@ -147,7 +147,7 @@ mod rustc {
             );
 
             let variant = adt_def.non_enum_variant();
-            let fields = match cv {
+            let fields = match cv.valtree {
                 ValTree::Branch(branch) => branch,
                 _ => {
                     return Some(Self {
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 51a7c976f60..4038a1d68fa 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -22,16 +22,16 @@ fn destructure_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     const_: ty::Const<'tcx>,
 ) -> ty::DestructuredConst<'tcx> {
-    let ty::ConstKind::Value(ct_ty, valtree) = const_.kind() else {
+    let ty::ConstKind::Value(cv) = const_.kind() else {
         bug!("cannot destructure constant {:?}", const_)
     };
 
-    let branches = match valtree {
+    let branches = match cv.valtree {
         ty::ValTree::Branch(b) => b,
         _ => bug!("cannot destructure constant {:?}", const_),
     };
 
-    let (fields, variant) = match ct_ty.kind() {
+    let (fields, variant) = match cv.ty.kind() {
         ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
             // construct the consts for the elements of the array/slice
             let field_consts = branches
@@ -116,6 +116,11 @@ fn recurse_build<'tcx>(
         | &ExprKind::ValueTypeAscription { source, .. } => {
             recurse_build(tcx, body, source, root_span)?
         }
+        &ExprKind::PlaceUnwrapUnsafeBinder { .. }
+        | &ExprKind::ValueUnwrapUnsafeBinder { .. }
+        | &ExprKind::WrapUnsafeBinder { .. } => {
+            todo!("FIXME(unsafe_binders)")
+        }
         &ExprKind::Literal { lit, neg } => {
             let sp = node.span;
             tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg })
@@ -347,6 +352,9 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
             | thir::ExprKind::Adt(_)
             | thir::ExprKind::PlaceTypeAscription { .. }
             | thir::ExprKind::ValueTypeAscription { .. }
+            | thir::ExprKind::PlaceUnwrapUnsafeBinder { .. }
+            | thir::ExprKind::ValueUnwrapUnsafeBinder { .. }
+            | thir::ExprKind::WrapUnsafeBinder { .. }
             | thir::ExprKind::Closure(_)
             | thir::ExprKind::Literal { .. }
             | thir::ExprKind::NonHirLiteral { .. }
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index d5e1937efaa..8c6e3c86bf5 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -225,7 +225,7 @@ fn resolve_associated_item<'tcx>(
             if trait_item_id != leaf_def.item.def_id
                 && let Some(leaf_def_item) = leaf_def.item.def_id.as_local()
             {
-                tcx.ensure().compare_impl_item(leaf_def_item)?;
+                tcx.ensure_ok().compare_impl_item(leaf_def_item)?;
             }
 
             Some(ty::Instance::new(leaf_def.item.def_id, args))
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index a04c7536118..2f258b23f2d 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -144,13 +144,13 @@ fn univariant_uninterned<'tcx>(
     cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
 }
 
-fn validate_const_with_value<'tcx>(
+fn extract_const_value<'tcx>(
     const_: ty::Const<'tcx>,
     ty: Ty<'tcx>,
     cx: &LayoutCx<'tcx>,
-) -> Result<ty::Const<'tcx>, &'tcx LayoutError<'tcx>> {
+) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
     match const_.kind() {
-        ty::ConstKind::Value(..) => Ok(const_),
+        ty::ConstKind::Value(cv) => Ok(cv),
         ty::ConstKind::Error(guar) => {
             return Err(error(cx, LayoutError::ReferencesError(guar)));
         }
@@ -209,13 +209,12 @@ fn layout_of_uncached<'tcx>(
                         &mut layout.backend_repr
                     {
                         if let Some(start) = start {
-                            scalar.valid_range_mut().start =
-                                validate_const_with_value(start, ty, cx)?
-                                    .try_to_bits(tcx, cx.typing_env)
-                                    .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
+                            scalar.valid_range_mut().start = extract_const_value(start, ty, cx)?
+                                .try_to_bits(tcx, cx.typing_env)
+                                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                         }
                         if let Some(end) = end {
-                            let mut end = validate_const_with_value(end, ty, cx)?
+                            let mut end = extract_const_value(end, ty, cx)?
                                 .try_to_bits(tcx, cx.typing_env)
                                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
                             if !include_end {
@@ -348,9 +347,7 @@ fn layout_of_uncached<'tcx>(
 
         // Arrays and slices.
         ty::Array(element, count) => {
-            let count = validate_const_with_value(count, ty, cx)?
-                .to_valtree()
-                .0
+            let count = extract_const_value(count, ty, cx)?
                 .try_to_target_usize(tcx)
                 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
 
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index 03dfe547ced..aafc0907ae1 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -31,7 +31,7 @@ pub enum ConstKind<I: Interner> {
     Unevaluated(ty::UnevaluatedConst<I>),
 
     /// Used to hold computed value.
-    Value(I::Ty, I::ValueConst),
+    Value(I::ValueConst),
 
     /// A placeholder for a const which could not be computed; this is
     /// propagated to avoid useless error messages.
@@ -52,7 +52,7 @@ impl<I: Interner> fmt::Debug for ConstKind<I> {
             Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var),
             Placeholder(placeholder) => write!(f, "{placeholder:?}"),
             Unevaluated(uv) => write!(f, "{uv:?}"),
-            Value(ty, valtree) => write!(f, "({valtree:?}: {ty:?})"),
+            Value(val) => write!(f, "{val:?}"),
             Error(_) => write!(f, "{{const error}}"),
             Expr(expr) => write!(f, "{expr:?}"),
         }
diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs
index 9b3ff14d507..9955e92b55a 100644
--- a/compiler/rustc_type_ir/src/fast_reject.rs
+++ b/compiler/rustc_type_ir/src/fast_reject.rs
@@ -483,8 +483,8 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
         };
 
         match lhs.kind() {
-            ty::ConstKind::Value(_, lhs_val) => match rhs.kind() {
-                ty::ConstKind::Value(_, rhs_val) => lhs_val == rhs_val,
+            ty::ConstKind::Value(lhs_val) => match rhs.kind() {
+                ty::ConstKind::Value(rhs_val) => lhs_val.valtree() == rhs_val.valtree(),
                 _ => false,
             },
 
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index d337a1a8ad9..711e42ff055 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -73,7 +73,7 @@ type Never = std::convert::Infallible;
 /// which means in practice almost every foldable type needs to also be
 /// visitable. (However, there are some types that are visitable without being
 /// foldable.)
-pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
+pub trait TypeFoldable<I: Interner>: TypeVisitable<I> + Clone {
     /// The entry point for folding. To fold a value `t` with a folder `f`
     /// call: `t.try_fold_with(f)`.
     ///
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 872cf668018..4e6d645e6fa 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -286,6 +286,11 @@ pub trait Const<I: Interner<Const = Self>>:
     }
 }
 
+pub trait ValueConst<I: Interner<ValueConst = Self>>: Copy + Debug + Hash + Eq {
+    fn ty(self) -> I::Ty;
+    fn valtree(self) -> I::ValTree;
+}
+
 pub trait ExprConst<I: Interner<ExprConst = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
     fn args(self) -> I::GenericArgs;
 }
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 0c3b0758f0f..a6c72da0c56 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -112,8 +112,9 @@ pub trait Interner:
     type PlaceholderConst: PlaceholderLike;
     type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
     type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
-    type ValueConst: Copy + Debug + Hash + Eq;
+    type ValueConst: ValueConst<Self>;
     type ExprConst: ExprConst<Self>;
+    type ValTree: Copy + Debug + Hash + Eq;
 
     // Kinds of regions
     type Region: Region<Self>;
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index e628b66d2f0..5b696ee5ed4 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -606,7 +606,9 @@ pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>(
             true
         }
         (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
-        (ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val,
+        (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
+            a_val.valtree() == b_val.valtree()
+        }
 
         // While this is slightly incorrect, it shouldn't matter for `min_const_generics`
         // and is the better alternative to waiting until `generic_const_exprs` can
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index 3213638afb2..0a074942170 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -59,7 +59,7 @@ use crate::{self as ty, Interner, TypeFlags};
 ///
 /// To implement this conveniently, use the derive macro located in
 /// `rustc_macros`.
-pub trait TypeVisitable<I: Interner>: fmt::Debug + Clone {
+pub trait TypeVisitable<I: Interner>: fmt::Debug {
     /// The entry point for visiting. To visit a value `t` with a visitor `v`
     /// call: `t.visit_with(v)`.
     ///
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index 8686169c15d..eec6cd8d49b 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -251,6 +251,7 @@ pub enum AssertMessage {
     ResumedAfterReturn(CoroutineKind),
     ResumedAfterPanic(CoroutineKind),
     MisalignedPointerDereference { required: Operand, found: Operand },
+    NullPointerDereference,
 }
 
 impl AssertMessage {
@@ -306,6 +307,7 @@ impl AssertMessage {
             AssertMessage::MisalignedPointerDereference { .. } => {
                 Ok("misaligned pointer dereference")
             }
+            AssertMessage::NullPointerDereference => Ok("null pointer dereference occured"),
         }
     }
 }
diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs
index 81981bce202..6638f93e555 100644
--- a/compiler/stable_mir/src/mir/pretty.rs
+++ b/compiler/stable_mir/src/mir/pretty.rs
@@ -298,6 +298,9 @@ fn pretty_assert_message<W: Write>(writer: &mut W, msg: &AssertMessage) -> io::R
                 "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}"
             )
         }
+        AssertMessage::NullPointerDereference => {
+            write!(writer, "\"null pointer dereference occured.\"")
+        }
         AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => {
             write!(writer, "{}", msg.description().unwrap())
         }
diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs
index 79efb83cebd..d985a98fcbf 100644
--- a/compiler/stable_mir/src/mir/visit.rs
+++ b/compiler/stable_mir/src/mir/visit.rs
@@ -426,7 +426,10 @@ pub trait MirVisitor {
             | AssertMessage::RemainderByZero(op) => {
                 self.visit_operand(op, location);
             }
-            AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => { //nothing to visit
+            AssertMessage::ResumedAfterReturn(_)
+            | AssertMessage::ResumedAfterPanic(_)
+            | AssertMessage::NullPointerDereference => {
+                //nothing to visit
             }
             AssertMessage::MisalignedPointerDereference { required, found } => {
                 self.visit_operand(required, location);
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 6815ac1c193..37f784a322c 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -600,8 +600,8 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
     /// no cleanup is done on any of the keys, values and other children.
     /// This decreases the height by 1 and is the opposite of `push_internal_level`.
     ///
-    /// Requires exclusive access to the `NodeRef` object but not to the root node;
-    /// it will not invalidate other handles or references to the root node.
+    /// Does not invalidate any handles or references pointing into the subtree
+    /// rooted at the first child of `self`.
     ///
     /// Panics if there is no internal level, i.e., if the root node is a leaf.
     pub(super) fn pop_internal_level<A: Allocator + Clone>(&mut self, alloc: A) {
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 0c9535dfaa6..b29f740ef0f 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -712,8 +712,8 @@ impl String {
         }
     }
 
-    /// Decode a UTF-16–encoded vector `v` into a `String`, returning [`Err`]
-    /// if `v` contains any invalid data.
+    /// Decode a native endian UTF-16–encoded vector `v` into a `String`,
+    /// returning [`Err`] if `v` contains any invalid data.
     ///
     /// # Examples
     ///
@@ -745,8 +745,8 @@ impl String {
         Ok(ret)
     }
 
-    /// Decode a UTF-16–encoded slice `v` into a `String`, replacing
-    /// invalid data with [the replacement character (`U+FFFD`)][U+FFFD].
+    /// Decode a native endian UTF-16–encoded slice `v` into a `String`,
+    /// replacing invalid data with [the replacement character (`U+FFFD`)][U+FFFD].
     ///
     /// Unlike [`from_utf8_lossy`] which returns a [`Cow<'a, str>`],
     /// `from_utf16_lossy` returns a `String` since the UTF-16 to UTF-8
@@ -777,8 +777,8 @@ impl String {
             .collect()
     }
 
-    /// Decode a UTF-16LE–encoded vector `v` into a `String`, returning [`Err`]
-    /// if `v` contains any invalid data.
+    /// Decode a UTF-16LE–encoded vector `v` into a `String`,
+    /// returning [`Err`] if `v` contains any invalid data.
     ///
     /// # Examples
     ///
@@ -852,8 +852,8 @@ impl String {
         }
     }
 
-    /// Decode a UTF-16BE–encoded vector `v` into a `String`, returning [`Err`]
-    /// if `v` contains any invalid data.
+    /// Decode a UTF-16BE–encoded vector `v` into a `String`,
+    /// returning [`Err`] if `v` contains any invalid data.
     ///
     /// # Examples
     ///
diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs
index aa841db045c..dcab6136ae8 100644
--- a/library/core/src/alloc/mod.rs
+++ b/library/core/src/alloc/mod.rs
@@ -49,26 +49,26 @@ impl fmt::Display for AllocError {
 /// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of
 /// data described via [`Layout`][].
 ///
-/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having
-/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
+/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers.
+/// An allocator for `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
 /// allocated memory.
 ///
-/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying
-/// allocator does not support this (like jemalloc) or return a null pointer (such as
-/// `libc::malloc`), this must be caught by the implementation.
+/// In contrast to [`GlobalAlloc`][], `Allocator` allows zero-sized allocations. If an underlying
+/// allocator does not support this (like jemalloc) or responds by returning a null pointer
+/// (such as `libc::malloc`), this must be caught by the implementation.
 ///
 /// ### Currently allocated memory
 ///
-/// Some of the methods require that a memory block be *currently allocated* via an allocator. This
-/// means that:
+/// Some of the methods require that a memory block is *currently allocated* by an allocator.
+/// This means that:
+///  * the starting address for that memory block was previously
+///    returned by [`allocate`], [`grow`], or [`shrink`], and
+///  * the memory block has not subsequently been deallocated.
 ///
-/// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or
-///   [`shrink`], and
-///
-/// * the memory block has not been subsequently deallocated, where blocks are either deallocated
-///   directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or
-///   [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
-///   remains valid.
+/// A memory block is deallocated by a call to [`deallocate`],
+/// or by a call to [`grow`] or [`shrink`] that returns `Ok`.
+/// A call to `grow` or `shrink` that returns `Err`,
+/// does not deallocate the memory block passed to it.
 ///
 /// [`allocate`]: Allocator::allocate
 /// [`grow`]: Allocator::grow
@@ -77,32 +77,28 @@ impl fmt::Display for AllocError {
 ///
 /// ### Memory fitting
 ///
-/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
-/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
+/// Some of the methods require that a `layout` *fit* a memory block or vice versa. This means that the
 /// following conditions must hold:
-///
-/// * The block must be allocated with the same alignment as [`layout.align()`], and
-///
-/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
-///   - `min` is the size of the layout most recently used to allocate the block, and
-///   - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`].
+///  * the memory block must be *currently allocated* with alignment of [`layout.align()`], and
+///  * [`layout.size()`] must fall in the range `min ..= max`, where:
+///    - `min` is the size of the layout used to allocate the block, and
+///    - `max` is the actual size returned from [`allocate`], [`grow`], or [`shrink`].
 ///
 /// [`layout.align()`]: Layout::align
 /// [`layout.size()`]: Layout::size
 ///
 /// # Safety
 ///
-/// * Memory blocks returned from an allocator that are [*currently allocated*] must point to
-///   valid memory and retain their validity while they are [*currently allocated*] and the shorter
-///   of:
-///   - the borrow-checker lifetime of the allocator type itself.
-///   - as long as at least one of the instance and all of its clones has not been dropped.
+/// Memory blocks that are [*currently allocated*] by an allocator,
+/// must point to valid memory, and retain their validity while until either:
+///  - the memory block is deallocated, or
+///  - the allocator is dropped.
 ///
-/// * copying, cloning, or moving the allocator must not invalidate memory blocks returned from this
-///   allocator. A copied or cloned allocator must behave like the same allocator, and
+/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it
+/// A copied or cloned allocator must behave like the original allocator.
 ///
-/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
-///   method of the allocator.
+/// A memory block which is [*currently allocated*] may be passed to
+/// any method of the allocator that accepts such an argument.
 ///
 /// [*currently allocated*]: #currently-allocated-memory
 #[unstable(feature = "allocator_api", issue = "32838")]
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index fb8a740aced..ccfdbf0eb70 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -92,7 +92,7 @@ impl char {
     #[stable(feature = "assoc_char_consts", since = "1.52.0")]
     pub const UNICODE_VERSION: (u8, u8, u8) = crate::unicode::UNICODE_VERSION;
 
-    /// Creates an iterator over the UTF-16 encoded code points in `iter`,
+    /// Creates an iterator over the native endian UTF-16 encoded code points in `iter`,
     /// returning unpaired surrogates as `Err`s.
     ///
     /// # Examples
@@ -704,7 +704,7 @@ impl char {
         unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) }
     }
 
-    /// Encodes this character as UTF-16 into the provided `u16` buffer,
+    /// Encodes this character as native endian UTF-16 into the provided `u16` buffer,
     /// and then returns the subslice of the buffer that contains the encoded character.
     ///
     /// # Panics
@@ -1828,7 +1828,7 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
     unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) }
 }
 
-/// Encodes a raw `u32` value as UTF-16 into the provided `u16` buffer,
+/// Encodes a raw `u32` value as native endian UTF-16 into the provided `u16` buffer,
 /// and then returns the subslice of the buffer that contains the encoded character.
 ///
 /// Unlike `char::encode_utf16`, this method also handles codepoints in the surrogate range.
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 97974d195fe..594236cf1d9 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -973,6 +973,24 @@ pub trait Ord: Eq + PartialOrd<Self> {
     /// assert_eq!(1.max(2), 2);
     /// assert_eq!(2.max(2), 2);
     /// ```
+    /// ```
+    /// use std::cmp::Ordering;
+    ///
+    /// #[derive(Eq)]
+    /// struct Equal(&'static str);
+    ///
+    /// impl PartialEq for Equal {
+    ///     fn eq(&self, other: &Self) -> bool { true }
+    /// }
+    /// impl PartialOrd for Equal {
+    ///     fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
+    /// }
+    /// impl Ord for Equal {
+    ///     fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
+    /// }
+    ///
+    /// assert_eq!(Equal("self").max(Equal("other")).0, "other");
+    /// ```
     #[stable(feature = "ord_max_min", since = "1.21.0")]
     #[inline]
     #[must_use]
@@ -981,7 +999,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
     where
         Self: Sized,
     {
-        max_by(self, other, Ord::cmp)
+        if other < self { self } else { other }
     }
 
     /// Compares and returns the minimum of two values.
@@ -994,6 +1012,24 @@ pub trait Ord: Eq + PartialOrd<Self> {
     /// assert_eq!(1.min(2), 1);
     /// assert_eq!(2.min(2), 2);
     /// ```
+    /// ```
+    /// use std::cmp::Ordering;
+    ///
+    /// #[derive(Eq)]
+    /// struct Equal(&'static str);
+    ///
+    /// impl PartialEq for Equal {
+    ///     fn eq(&self, other: &Self) -> bool { true }
+    /// }
+    /// impl PartialOrd for Equal {
+    ///     fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
+    /// }
+    /// impl Ord for Equal {
+    ///     fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
+    /// }
+    ///
+    /// assert_eq!(Equal("self").min(Equal("other")).0, "self");
+    /// ```
     #[stable(feature = "ord_max_min", since = "1.21.0")]
     #[inline]
     #[must_use]
@@ -1002,7 +1038,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
     where
         Self: Sized,
     {
-        min_by(self, other, Ord::cmp)
+        if other < self { other } else { self }
     }
 
     /// Restrict a value to a certain interval.
@@ -1414,6 +1450,24 @@ pub macro PartialOrd($item:item) {
 /// assert_eq!(cmp::min(1, 2), 1);
 /// assert_eq!(cmp::min(2, 2), 2);
 /// ```
+/// ```
+/// use std::cmp::{self, Ordering};
+///
+/// #[derive(Eq)]
+/// struct Equal(&'static str);
+///
+/// impl PartialEq for Equal {
+///     fn eq(&self, other: &Self) -> bool { true }
+/// }
+/// impl PartialOrd for Equal {
+///     fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
+/// }
+/// impl Ord for Equal {
+///     fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
+/// }
+///
+/// assert_eq!(cmp::min(Equal("v1"), Equal("v2")).0, "v1");
+/// ```
 #[inline]
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1431,20 +1485,22 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
 /// ```
 /// use std::cmp;
 ///
-/// let result = cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs()));
-/// assert_eq!(result, 1);
+/// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs());
 ///
-/// let result = cmp::min_by(-2, 3, |x: &i32, y: &i32| x.abs().cmp(&y.abs()));
-/// assert_eq!(result, -2);
+/// let result = cmp::min_by(2, -1, abs_cmp);
+/// assert_eq!(result, -1);
+///
+/// let result = cmp::min_by(2, -3, abs_cmp);
+/// assert_eq!(result, 2);
+///
+/// let result = cmp::min_by(1, -1, abs_cmp);
+/// assert_eq!(result, 1);
 /// ```
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
 pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
-    match compare(&v1, &v2) {
-        Ordering::Less | Ordering::Equal => v1,
-        Ordering::Greater => v2,
-    }
+    if compare(&v2, &v1).is_lt() { v2 } else { v1 }
 }
 
 /// Returns the element that gives the minimum value from the specified function.
@@ -1456,17 +1512,20 @@ pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
 /// ```
 /// use std::cmp;
 ///
-/// let result = cmp::min_by_key(-2, 1, |x: &i32| x.abs());
-/// assert_eq!(result, 1);
+/// let result = cmp::min_by_key(2, -1, |x: &i32| x.abs());
+/// assert_eq!(result, -1);
 ///
-/// let result = cmp::min_by_key(-2, 2, |x: &i32| x.abs());
-/// assert_eq!(result, -2);
+/// let result = cmp::min_by_key(2, -3, |x: &i32| x.abs());
+/// assert_eq!(result, 2);
+///
+/// let result = cmp::min_by_key(1, -1, |x: &i32| x.abs());
+/// assert_eq!(result, 1);
 /// ```
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
 pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
-    min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
+    if f(&v2) < f(&v1) { v2 } else { v1 }
 }
 
 /// Compares and returns the maximum of two values.
@@ -1483,6 +1542,24 @@ pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
 /// assert_eq!(cmp::max(1, 2), 2);
 /// assert_eq!(cmp::max(2, 2), 2);
 /// ```
+/// ```
+/// use std::cmp::{self, Ordering};
+///
+/// #[derive(Eq)]
+/// struct Equal(&'static str);
+///
+/// impl PartialEq for Equal {
+///     fn eq(&self, other: &Self) -> bool { true }
+/// }
+/// impl PartialOrd for Equal {
+///     fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
+/// }
+/// impl Ord for Equal {
+///     fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
+/// }
+///
+/// assert_eq!(cmp::max(Equal("v1"), Equal("v2")).0, "v2");
+/// ```
 #[inline]
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1500,20 +1577,22 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
 /// ```
 /// use std::cmp;
 ///
-/// let result = cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs()));
+/// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs());
+///
+/// let result = cmp::max_by(3, -2, abs_cmp) ;
+/// assert_eq!(result, 3);
+///
+/// let result = cmp::max_by(1, -2, abs_cmp);
 /// assert_eq!(result, -2);
 ///
-/// let result = cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())) ;
-/// assert_eq!(result, 2);
+/// let result = cmp::max_by(1, -1, abs_cmp);
+/// assert_eq!(result, -1);
 /// ```
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
 pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
-    match compare(&v1, &v2) {
-        Ordering::Less | Ordering::Equal => v2,
-        Ordering::Greater => v1,
-    }
+    if compare(&v2, &v1).is_lt() { v1 } else { v2 }
 }
 
 /// Returns the element that gives the maximum value from the specified function.
@@ -1525,17 +1604,20 @@ pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
 /// ```
 /// use std::cmp;
 ///
-/// let result = cmp::max_by_key(-2, 1, |x: &i32| x.abs());
+/// let result = cmp::max_by_key(3, -2, |x: &i32| x.abs());
+/// assert_eq!(result, 3);
+///
+/// let result = cmp::max_by_key(1, -2, |x: &i32| x.abs());
 /// assert_eq!(result, -2);
 ///
-/// let result = cmp::max_by_key(-2, 2, |x: &i32| x.abs());
-/// assert_eq!(result, 2);
+/// let result = cmp::max_by_key(1, -1, |x: &i32| x.abs());
+/// assert_eq!(result, -1);
 /// ```
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
 pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
-    max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
+    if f(&v2) < f(&v1) { v1 } else { v2 }
 }
 
 /// Compares and sorts two values, returning minimum and maximum.
@@ -1549,13 +1631,32 @@ pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
 /// use std::cmp;
 ///
 /// assert_eq!(cmp::minmax(1, 2), [1, 2]);
-/// assert_eq!(cmp::minmax(2, 2), [2, 2]);
+/// assert_eq!(cmp::minmax(2, 1), [1, 2]);
 ///
 /// // You can destructure the result using array patterns
 /// let [min, max] = cmp::minmax(42, 17);
 /// assert_eq!(min, 17);
 /// assert_eq!(max, 42);
 /// ```
+/// ```
+/// #![feature(cmp_minmax)]
+/// use std::cmp::{self, Ordering};
+///
+/// #[derive(Eq)]
+/// struct Equal(&'static str);
+///
+/// impl PartialEq for Equal {
+///     fn eq(&self, other: &Self) -> bool { true }
+/// }
+/// impl PartialOrd for Equal {
+///     fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
+/// }
+/// impl Ord for Equal {
+///     fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
+/// }
+///
+/// assert_eq!(cmp::minmax(Equal("v1"), Equal("v2")).map(|v| v.0), ["v1", "v2"]);
+/// ```
 #[inline]
 #[must_use]
 #[unstable(feature = "cmp_minmax", issue = "115939")]
@@ -1563,7 +1664,7 @@ pub fn minmax<T>(v1: T, v2: T) -> [T; 2]
 where
     T: Ord,
 {
-    if v1 <= v2 { [v1, v2] } else { [v2, v1] }
+    if v2 < v1 { [v2, v1] } else { [v1, v2] }
 }
 
 /// Returns minimum and maximum values with respect to the specified comparison function.
@@ -1576,11 +1677,14 @@ where
 /// #![feature(cmp_minmax)]
 /// use std::cmp;
 ///
-/// assert_eq!(cmp::minmax_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [1, -2]);
-/// assert_eq!(cmp::minmax_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [-2, 2]);
+/// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs());
+///
+/// assert_eq!(cmp::minmax_by(-2, 1, abs_cmp), [1, -2]);
+/// assert_eq!(cmp::minmax_by(-1, 2, abs_cmp), [-1, 2]);
+/// assert_eq!(cmp::minmax_by(-2, 2, abs_cmp), [-2, 2]);
 ///
 /// // You can destructure the result using array patterns
-/// let [min, max] = cmp::minmax_by(-42, 17, |x: &i32, y: &i32| x.abs().cmp(&y.abs()));
+/// let [min, max] = cmp::minmax_by(-42, 17, abs_cmp);
 /// assert_eq!(min, 17);
 /// assert_eq!(max, -42);
 /// ```
@@ -1591,7 +1695,7 @@ pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2]
 where
     F: FnOnce(&T, &T) -> Ordering,
 {
-    if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] }
+    if compare(&v2, &v1).is_lt() { [v2, v1] } else { [v1, v2] }
 }
 
 /// Returns minimum and maximum values with respect to the specified key function.
@@ -1620,7 +1724,7 @@ where
     F: FnMut(&T) -> K,
     K: Ord,
 {
-    minmax_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
+    if f(&v2) < f(&v1) { [v2, v1] } else { [v1, v2] }
 }
 
 // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 80f6e32b6b2..e5c1a64c12e 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -468,9 +468,11 @@ pub fn spin_loop() {
 /// // No assumptions can be made about either operand, so the multiplication is not optimized out.
 /// let y = black_box(5) * black_box(10);
 /// ```
+///
+/// During constant evaluation, `black_box` is treated as a no-op.
 #[inline]
 #[stable(feature = "bench_black_box", since = "1.66.0")]
-#[rustc_const_unstable(feature = "const_black_box", issue = "none")]
+#[rustc_const_stable(feature = "const_black_box", since = "CURRENT_RUSTC_VERSION")]
 pub const fn black_box<T>(dummy: T) -> T {
     crate::intrinsics::black_box(dummy)
 }
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 41b2ffad668..bf07632d992 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -78,7 +78,11 @@ pub mod simd;
 use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering};
 
 #[stable(feature = "drop_in_place", since = "1.8.0")]
-#[rustc_allowed_through_unstable_modules]
+#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)]
+#[cfg_attr(
+    not(bootstrap),
+    rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"
+)]
 #[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")]
 #[inline]
 pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
@@ -3725,6 +3729,7 @@ pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: u
 #[rustc_nounwind]
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
+#[rustc_intrinsic_const_stable_indirect]
 pub const fn black_box<T>(_dummy: T) -> T {
     unimplemented!()
 }
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 01a3c9d2ada..3669051ce82 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1831,32 +1831,4 @@ pub(crate) mod builtin {
     pub macro deref($pat:pat) {
         builtin # deref($pat)
     }
-
-    /// Derive macro for `rustc-serialize`. Should not be used in new code.
-    #[rustc_builtin_macro]
-    #[unstable(
-        feature = "rustc_encodable_decodable",
-        issue = "none",
-        soft,
-        reason = "derive macro for `rustc-serialize`; should not be used in new code"
-    )]
-    #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")]
-    #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
-    pub macro RustcDecodable($item:item) {
-        /* compiler built-in */
-    }
-
-    /// Derive macro for `rustc-serialize`. Should not be used in new code.
-    #[rustc_builtin_macro]
-    #[unstable(
-        feature = "rustc_encodable_decodable",
-        issue = "none",
-        soft,
-        reason = "derive macro for `rustc-serialize`; should not be used in new code"
-    )]
-    #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")]
-    #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
-    pub macro RustcEncodable($item:item) {
-        /* compiler built-in */
-    }
 }
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index a793fc2aa2e..18ada14d101 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -1091,7 +1091,195 @@ pub trait FnPtr: Copy + Clone {
     fn addr(self) -> *const ();
 }
 
-/// Derive macro generating impls of traits related to smart pointers.
+/// Derive macro that makes a smart pointer usable with trait objects.
+///
+/// # What this macro does
+///
+/// This macro is intended to be used with user-defined pointer types, and makes it possible to
+/// perform coercions on the pointee of the user-defined pointer. There are two aspects to this:
+///
+/// ## Unsizing coercions of the pointee
+///
+/// By using the macro, the following example will compile:
+/// ```
+/// #![feature(derive_coerce_pointee)]
+/// use std::marker::CoercePointee;
+/// use std::ops::Deref;
+///
+/// #[derive(CoercePointee)]
+/// #[repr(transparent)]
+/// struct MySmartPointer<T: ?Sized>(Box<T>);
+///
+/// impl<T: ?Sized> Deref for MySmartPointer<T> {
+///     type Target = T;
+///     fn deref(&self) -> &T {
+///         &self.0
+///     }
+/// }
+///
+/// trait MyTrait {}
+///
+/// impl MyTrait for i32 {}
+///
+/// fn main() {
+///     let ptr: MySmartPointer<i32> = MySmartPointer(Box::new(4));
+///
+///     // This coercion would be an error without the derive.
+///     let ptr: MySmartPointer<dyn MyTrait> = ptr;
+/// }
+/// ```
+/// Without the `#[derive(CoercePointee)]` macro, this example would fail with the following error:
+/// ```text
+/// error[E0308]: mismatched types
+///   --> src/main.rs:11:44
+///    |
+/// 11 |     let ptr: MySmartPointer<dyn MyTrait> = ptr;
+///    |              ---------------------------   ^^^ expected `MySmartPointer<dyn MyTrait>`, found `MySmartPointer<i32>`
+///    |              |
+///    |              expected due to this
+///    |
+///    = note: expected struct `MySmartPointer<dyn MyTrait>`
+///               found struct `MySmartPointer<i32>`
+///    = help: `i32` implements `MyTrait` so you could box the found value and coerce it to the trait object `Box<dyn MyTrait>`, you will have to change the expected type as well
+/// ```
+///
+/// ## Dyn compatibility
+///
+/// This macro allows you to dispatch on the user-defined pointer type. That is, traits using the
+/// type as a receiver are dyn-compatible. For example, this compiles:
+///
+/// ```
+/// #![feature(arbitrary_self_types, derive_coerce_pointee)]
+/// use std::marker::CoercePointee;
+/// use std::ops::Deref;
+///
+/// #[derive(CoercePointee)]
+/// #[repr(transparent)]
+/// struct MySmartPointer<T: ?Sized>(Box<T>);
+///
+/// impl<T: ?Sized> Deref for MySmartPointer<T> {
+///     type Target = T;
+///     fn deref(&self) -> &T {
+///         &self.0
+///     }
+/// }
+///
+/// // You can always define this trait. (as long as you have #![feature(arbitrary_self_types)])
+/// trait MyTrait {
+///     fn func(self: MySmartPointer<Self>);
+/// }
+///
+/// // But using `dyn MyTrait` requires #[derive(CoercePointee)].
+/// fn call_func(value: MySmartPointer<dyn MyTrait>) {
+///     value.func();
+/// }
+/// ```
+/// If you remove the `#[derive(CoercePointee)]` annotation from the struct, then the above example
+/// will fail with this error message:
+/// ```text
+/// error[E0038]: the trait `MyTrait` is not dyn compatible
+///   --> src/lib.rs:21:36
+///    |
+/// 17 |     fn func(self: MySmartPointer<Self>);
+///    |                   -------------------- help: consider changing method `func`'s `self` parameter to be `&self`: `&Self`
+/// ...
+/// 21 | fn call_func(value: MySmartPointer<dyn MyTrait>) {
+///    |                                    ^^^^^^^^^^^ `MyTrait` is not dyn compatible
+///    |
+/// note: for a trait to be dyn compatible it needs to allow building a vtable
+///       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+///   --> src/lib.rs:17:19
+///    |
+/// 16 | trait MyTrait {
+///    |       ------- this trait is not dyn compatible...
+/// 17 |     fn func(self: MySmartPointer<Self>);
+///    |                   ^^^^^^^^^^^^^^^^^^^^ ...because method `func`'s `self` parameter cannot be dispatched on
+/// ```
+///
+/// # Requirements for using the macro
+///
+/// This macro can only be used if:
+/// * The type is a `#[repr(transparent)]` struct.
+/// * The type of its non-zero-sized field must either be a standard library pointer type
+///   (reference, raw pointer, `NonNull`, `Box`, `Rc`, `Arc`, etc.) or another user-defined type
+///   also using the `#[derive(CoercePointee)]` macro.
+/// * Zero-sized fields must not mention any generic parameters unless the zero-sized field has
+///   type [`PhantomData`].
+///
+/// ## Multiple type parameters
+///
+/// If the type has multiple type parameters, then you must explicitly specify which one should be
+/// used for dynamic dispatch. For example:
+/// ```
+/// # #![feature(derive_coerce_pointee)]
+/// # use std::marker::{CoercePointee, PhantomData};
+/// #[derive(CoercePointee)]
+/// #[repr(transparent)]
+/// struct MySmartPointer<#[pointee] T: ?Sized, U> {
+///     ptr: Box<T>,
+///     _phantom: PhantomData<U>,
+/// }
+/// ```
+/// Specifying `#[pointee]` when the struct has only one type parameter is allowed, but not required.
+///
+/// # Examples
+///
+/// A custom implementation of the `Rc` type:
+/// ```
+/// #![feature(derive_coerce_pointee)]
+/// use std::marker::CoercePointee;
+/// use std::ops::Deref;
+/// use std::ptr::NonNull;
+///
+/// #[derive(CoercePointee)]
+/// #[repr(transparent)]
+/// pub struct Rc<T: ?Sized> {
+///     inner: NonNull<RcInner<T>>,
+/// }
+///
+/// struct RcInner<T: ?Sized> {
+///     refcount: usize,
+///     value: T,
+/// }
+///
+/// impl<T: ?Sized> Deref for Rc<T> {
+///     type Target = T;
+///     fn deref(&self) -> &T {
+///         let ptr = self.inner.as_ptr();
+///         unsafe { &(*ptr).value }
+///     }
+/// }
+///
+/// impl<T> Rc<T> {
+///     pub fn new(value: T) -> Self {
+///         let inner = Box::new(RcInner {
+///             refcount: 1,
+///             value,
+///         });
+///         Self {
+///             inner: NonNull::from(Box::leak(inner)),
+///         }
+///     }
+/// }
+///
+/// impl<T: ?Sized> Clone for Rc<T> {
+///     fn clone(&self) -> Self {
+///         // A real implementation would handle overflow here.
+///         unsafe { (*self.inner.as_ptr()).refcount += 1 };
+///         Self { inner: self.inner }
+///     }
+/// }
+///
+/// impl<T: ?Sized> Drop for Rc<T> {
+///     fn drop(&mut self) {
+///         let ptr = self.inner.as_ptr();
+///         unsafe { (*ptr).refcount -= 1 };
+///         if unsafe { (*ptr).refcount } == 0 {
+///             drop(unsafe { Box::from_raw(ptr) });
+///         }
+///     }
+/// }
+/// ```
 #[rustc_builtin_macro(CoercePointee, attributes(pointee))]
 #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
 #[unstable(feature = "derive_coerce_pointee", issue = "123430")]
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index ac5307a671d..0d8c3ef906b 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -276,10 +276,9 @@ impl<T: Copy> Clone for MaybeUninit<T> {
 impl<T> fmt::Debug for MaybeUninit<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // NB: there is no `.pad_fmt` so we can't use a simpler `format_args!("MaybeUninit<{..}>").
-        // This needs to be adjusted if `MaybeUninit` moves modules.
         let full_name = type_name::<Self>();
-        let short_name = full_name.split_once("mem::maybe_uninit::").unwrap().1;
-        f.pad(short_name)
+        let prefix_len = full_name.find("MaybeUninit").unwrap();
+        f.pad(&full_name[prefix_len..])
     }
 }
 
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 8fb1588e60b..5e45974b3d4 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -670,7 +670,8 @@ impl f128 {
     /// If one of the arguments is NaN, then the other argument is returned.
     /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
     /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
-    /// This also matches the behavior of libm’s fmax.
+    /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal
+    /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
     ///
     /// ```
     /// #![feature(f128)]
@@ -696,7 +697,8 @@ impl f128 {
     /// If one of the arguments is NaN, then the other argument is returned.
     /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
     /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
-    /// This also matches the behavior of libm’s fmin.
+    /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal
+    /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
     ///
     /// ```
     /// #![feature(f128)]
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 8c2af74b8f8..e3176cd1688 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -662,7 +662,8 @@ impl f16 {
     /// If one of the arguments is NaN, then the other argument is returned.
     /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
     /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
-    /// This also matches the behavior of libm’s fmax.
+    /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal
+    /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
     ///
     /// ```
     /// #![feature(f16)]
@@ -687,7 +688,8 @@ impl f16 {
     /// If one of the arguments is NaN, then the other argument is returned.
     /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
     /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
-    /// This also matches the behavior of libm’s fmin.
+    /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal
+    /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
     ///
     /// ```
     /// #![feature(f16)]
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 817bedbd44f..4d42997369f 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -874,7 +874,8 @@ impl f32 {
     /// If one of the arguments is NaN, then the other argument is returned.
     /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
     /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
-    /// This also matches the behavior of libm’s fmax.
+    /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal
+    /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
     ///
     /// ```
     /// let x = 1.0f32;
@@ -895,7 +896,8 @@ impl f32 {
     /// If one of the arguments is NaN, then the other argument is returned.
     /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
     /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
-    /// This also matches the behavior of libm’s fmin.
+    /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal
+    /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
     ///
     /// ```
     /// let x = 1.0f32;
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 1b0651a0def..907971d303f 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -892,7 +892,8 @@ impl f64 {
     /// If one of the arguments is NaN, then the other argument is returned.
     /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
     /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
-    /// This also matches the behavior of libm’s fmax.
+    /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal
+    /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
     ///
     /// ```
     /// let x = 1.0_f64;
@@ -913,7 +914,8 @@ impl f64 {
     /// If one of the arguments is NaN, then the other argument is returned.
     /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
     /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
-    /// This also matches the behavior of libm’s fmin.
+    /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal
+    /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically.
     ///
     /// ```
     /// let x = 1.0_f64;
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 6c1b568e231..55f4ccd958e 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -1322,20 +1322,6 @@ pub enum FpCategory {
     Normal,
 }
 
-macro_rules! from_str_radix_int_impl {
-    ($($t:ty)*) => {$(
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl FromStr for $t {
-            type Err = ParseIntError;
-            #[inline]
-            fn from_str(src: &str) -> Result<Self, ParseIntError> {
-                <$t>::from_str_radix(src, 10)
-            }
-        }
-    )*}
-}
-from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
-
 /// 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
@@ -1351,18 +1337,58 @@ pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8])
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-const fn from_str_radix_panic(radix: u32) -> ! {
+const fn from_ascii_radix_panic(radix: u32) -> ! {
     const_panic!(
-        "from_str_radix_int: must lie in the range `[2, 36]`",
-        "from_str_radix_int: must lie in the range `[2, 36]` - found {radix}",
+        "from_ascii_radix: radix must lie in the range `[2, 36]`",
+        "from_ascii_radix: radix must lie in the range `[2, 36]` - found {radix}",
         radix: u32 = radix,
     )
 }
 
-macro_rules! from_str_radix {
+macro_rules! from_str_int_impl {
     ($signedness:ident $($int_ty:ty)+) => {$(
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl FromStr for $int_ty {
+            type Err = ParseIntError;
+
+            /// Parses an integer from a string slice with decimal digits.
+            ///
+            /// The characters are expected to be an optional
+            #[doc = sign_dependent_expr!{
+                $signedness ?
+                if signed {
+                    " `+` or `-` "
+                }
+                if unsigned {
+                    " `+` "
+                }
+            }]
+            /// sign followed by only digits. Leading and trailing non-digit characters (including
+            /// whitespace) represent an error. Underscores (which are accepted in Rust literals)
+            /// also represent an error.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            /// ```
+            /// use std::str::FromStr;
+            ///
+            #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str(\"+10\"), Ok(10));")]
+            /// ```
+            /// Trailing space returns error:
+            /// ```
+            /// # use std::str::FromStr;
+            /// #
+            #[doc = concat!("assert!(", stringify!($int_ty), "::from_str(\"1 \").is_err());")]
+            /// ```
+            #[inline]
+            fn from_str(src: &str) -> Result<$int_ty, ParseIntError> {
+                <$int_ty>::from_str_radix(src, 10)
+            }
+        }
+
         impl $int_ty {
-            /// Converts a string slice in a given base to an integer.
+            /// Parses an integer from a string slice with digits in a given base.
             ///
             /// The string is expected to be an optional
             #[doc = sign_dependent_expr!{
@@ -1375,7 +1401,7 @@ macro_rules! from_str_radix {
                 }
             }]
             /// sign followed by only digits. Leading and trailing non-digit characters (including
-            /// whitespace) represent an error. Underscores (which are accepted in rust literals)
+            /// whitespace) represent an error. Underscores (which are accepted in Rust literals)
             /// also represent an error.
             ///
             /// Digits are a subset of these characters, depending on `radix`:
@@ -1401,11 +1427,92 @@ macro_rules! from_str_radix {
             #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")]
             #[inline]
             pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> {
+                <$int_ty>::from_ascii_radix(src.as_bytes(), radix)
+            }
+
+            /// Parses an integer from an ASCII-byte slice with decimal digits.
+            ///
+            /// The characters are expected to be an optional
+            #[doc = sign_dependent_expr!{
+                $signedness ?
+                if signed {
+                    " `+` or `-` "
+                }
+                if unsigned {
+                    " `+` "
+                }
+            }]
+            /// sign followed by only digits. Leading and trailing non-digit characters (including
+            /// whitespace) represent an error. Underscores (which are accepted in Rust literals)
+            /// also represent an error.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            /// ```
+            /// #![feature(int_from_ascii)]
+            ///
+            #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_ascii(b\"+10\"), Ok(10));")]
+            /// ```
+            /// Trailing space returns error:
+            /// ```
+            /// # #![feature(int_from_ascii)]
+            /// #
+            #[doc = concat!("assert!(", stringify!($int_ty), "::from_ascii(b\"1 \").is_err());")]
+            /// ```
+            #[unstable(feature = "int_from_ascii", issue = "134821")]
+            #[inline]
+            pub const fn from_ascii(src: &[u8]) -> Result<$int_ty, ParseIntError> {
+                <$int_ty>::from_ascii_radix(src, 10)
+            }
+
+            /// Parses an integer from an ASCII-byte slice with digits in a given base.
+            ///
+            /// The characters are expected to be an optional
+            #[doc = sign_dependent_expr!{
+                $signedness ?
+                if signed {
+                    " `+` or `-` "
+                }
+                if unsigned {
+                    " `+` "
+                }
+            }]
+            /// sign followed by only digits. Leading and trailing non-digit characters (including
+            /// whitespace) represent an error. Underscores (which are accepted in Rust literals)
+            /// also 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:
+            /// ```
+            /// #![feature(int_from_ascii)]
+            ///
+            #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_ascii_radix(b\"A\", 16), Ok(10));")]
+            /// ```
+            /// Trailing space returns error:
+            /// ```
+            /// # #![feature(int_from_ascii)]
+            /// #
+            #[doc = concat!("assert!(", stringify!($int_ty), "::from_ascii_radix(b\"1 \", 10).is_err());")]
+            /// ```
+            #[unstable(feature = "int_from_ascii", issue = "134821")]
+            #[inline]
+            pub const fn from_ascii_radix(src: &[u8], radix: u32) -> Result<$int_ty, ParseIntError> {
                 use self::IntErrorKind::*;
                 use self::ParseIntError as PIE;
 
                 if 2 > radix || radix > 36 {
-                    from_str_radix_panic(radix);
+                    from_ascii_radix_panic(radix);
                 }
 
                 if src.is_empty() {
@@ -1415,12 +1522,6 @@ macro_rules! from_str_radix {
                 #[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 });
@@ -1496,67 +1597,8 @@ macro_rules! from_str_radix {
                 Ok(result)
             }
         }
-    )+}
-}
-
-from_str_radix! { unsigned u8 u16 u32 u64 u128 }
-from_str_radix! { signed i8 i16 i32 i64 i128 }
-
-// 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 {
-    ($($signedness:ident $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
-        #[doc = sign_dependent_expr!{
-            $signedness ?
-            if signed {
-                " `+` or `-` "
-            }
-            if unsigned {
-                " `+` "
-            }
-        }]
-        /// sign followed by only digits. Leading and trailing non-digit characters (including
-        /// whitespace) represent an error. Underscores (which are accepted in rust literals)
-        /// also 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));")]
-        /// ```
-        /// Trailing space returns error:
-        /// ```
-        #[doc = concat!("assert!(", stringify!($size), "::from_str_radix(\"1 \", 10).is_err());")]
-        /// ```
-        #[stable(feature = "rust1", since = "1.0.0")]
-        #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")]
-        #[inline]
-        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),
-            }
-        }
-    })*}
+    )*}
 }
 
-#[cfg(target_pointer_width = "16")]
-from_str_radix_size_impl! { signed i16 isize, unsigned u16 usize }
-#[cfg(target_pointer_width = "32")]
-from_str_radix_size_impl! { signed i32 isize, unsigned u32 usize }
-#[cfg(target_pointer_width = "64")]
-from_str_radix_size_impl! { signed i64 isize, unsigned u64 usize }
+from_str_int_impl! { signed isize i8 i16 i32 i64 i128 }
+from_str_int_impl! { unsigned usize u8 u16 u32 u64 u128 }
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 53e2b238bae..a89de12c02b 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -291,6 +291,22 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
     )
 }
 
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[track_caller]
+#[cfg_attr(not(bootstrap), lang = "panic_null_pointer_dereference")] // needed by codegen for panic on null pointer deref
+#[rustc_nounwind] // `CheckNull` MIR pass requires this function to never unwind
+fn panic_null_pointer_dereference() -> ! {
+    if cfg!(feature = "panic_immediate_abort") {
+        super::intrinsics::abort()
+    }
+
+    panic_nounwind_fmt(
+        format_args!("null pointer dereference occured"),
+        /* force_no_backtrace */ false,
+    )
+}
+
 /// Panics because we cannot unwind out of a function.
 ///
 /// This is a separate function to avoid the codesize impact of each crate containing the string to
diff --git a/library/core/src/prelude/common.rs b/library/core/src/prelude/common.rs
index e38ef1e147c..8b116cecb52 100644
--- a/library/core/src/prelude/common.rs
+++ b/library/core/src/prelude/common.rs
@@ -12,6 +12,9 @@ pub use crate::marker::{Copy, Send, Sized, Sync, Unpin};
 #[stable(feature = "core_prelude", since = "1.4.0")]
 #[doc(no_inline)]
 pub use crate::ops::{Drop, Fn, FnMut, FnOnce};
+#[stable(feature = "async_closure", since = "1.85.0")]
+#[doc(no_inline)]
+pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
 
 // Re-exported functions
 #[stable(feature = "core_prelude", since = "1.4.0")]
diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs
index d3fda1cd273..0ab97f5bbd5 100644
--- a/library/core/src/prelude/mod.rs
+++ b/library/core/src/prelude/mod.rs
@@ -18,16 +18,6 @@ mod common;
 pub mod v1 {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::common::*;
-
-    // Do not `doc(inline)` these `doc(hidden)` items.
-    #[unstable(
-        feature = "rustc_encodable_decodable",
-        issue = "none",
-        soft,
-        reason = "derive macro for `rustc-serialize`; should not be used in new code"
-    )]
-    #[allow(deprecated)]
-    pub use crate::macros::builtin::{RustcDecodable, RustcEncodable};
 }
 
 /// The 2015 version of the core prelude.
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index c5f029363e5..bbf5939fe1b 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1160,9 +1160,9 @@ impl<T> (T,) {}
 ///
 /// Note that most common platforms will not support `f16` in hardware without enabling extra target
 /// features, with the notable exception of Apple Silicon (also known as M1, M2, etc.) processors.
-/// Hardware support on x86-64 requires the avx512fp16 feature, while RISC-V requires Zhf.
-/// Usually the fallback implementation will be to use `f32` hardware if it exists, and convert
-/// between `f16` and `f32` when performing math.
+/// Hardware support on x86/x86-64 requires the avx512fp16 or avx10.1 features, while RISC-V requires
+/// Zfh, and Arm/AArch64 requires FEAT_FP16.  Usually the fallback implementation will be to use `f32`
+/// hardware if it exists, and convert between `f16` and `f32` when performing math.
 ///
 /// *[See also the `std::f16::consts` module](crate::f16::consts).*
 ///
@@ -1344,10 +1344,10 @@ mod prim_f64 {}
 /// quad-precision values][wikipedia] for more information.
 ///
 /// Note that no platforms have hardware support for `f128` without enabling target specific features,
-/// as for all instruction set architectures `f128` is considered an optional feature.
-/// Only Power ISA ("PowerPC") and RISC-V specify it, and only certain microarchitectures
-/// actually implement it. For x86-64 and AArch64, ISA support is not even specified,
-/// so it will always be a software implementation significantly slower than `f64`.
+/// as for all instruction set architectures `f128` is considered an optional feature.  Only Power ISA
+/// ("PowerPC") and RISC-V (via the Q extension) specify it, and only certain microarchitectures
+/// actually implement it. For x86-64 and AArch64, ISA support is not even specified, so it will always
+/// be a software implementation significantly slower than `f64`.
 ///
 /// _Note: `f128` support is incomplete. Many platforms will not be able to link math functions. On
 /// x86 in particular, these functions do link but their results are always incorrect._
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index ec569291853..0c6eaf60d04 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1681,7 +1681,7 @@ impl<T, const N: usize> *const [T; N] {
     }
 }
 
-// Equality for pointers
+/// Pointer equality is by address, as produced by the [`<*const T>::addr`](pointer::addr) method.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialEq for *const T {
     #[inline]
@@ -1691,10 +1691,11 @@ impl<T: ?Sized> PartialEq for *const T {
     }
 }
 
+/// Pointer equality is an equivalence relation.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Eq for *const T {}
 
-// Comparison for pointers
+/// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Ord for *const T {
     #[inline]
@@ -1710,6 +1711,7 @@ impl<T: ?Sized> Ord for *const T {
     }
 }
 
+/// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialOrd for *const T {
     #[inline]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 5d9d337f101..d1b0104c0fa 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -2097,7 +2097,7 @@ impl<T, const N: usize> *mut [T; N] {
     }
 }
 
-// Equality for pointers
+/// Pointer equality is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialEq for *mut T {
     #[inline(always)]
@@ -2107,9 +2107,11 @@ impl<T: ?Sized> PartialEq for *mut T {
     }
 }
 
+/// Pointer equality is an equivalence relation.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Eq for *mut T {}
 
+/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Ord for *mut T {
     #[inline]
@@ -2125,6 +2127,7 @@ impl<T: ?Sized> Ord for *mut T {
     }
 }
 
+/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialOrd for *mut T {
     #[inline(always)]
diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs
index d8e0acb565c..5d5ee4c7b62 100644
--- a/library/core/src/slice/rotate.rs
+++ b/library/core/src/slice/rotate.rs
@@ -1,6 +1,8 @@
 use crate::mem::{self, MaybeUninit, SizedTypeProperties};
 use crate::{cmp, ptr};
 
+type BufType = [usize; 32];
+
 /// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first
 /// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the
 /// right.
@@ -8,14 +10,82 @@ use crate::{cmp, ptr};
 /// # Safety
 ///
 /// The specified range must be valid for reading and writing.
+#[inline]
+pub(super) unsafe fn ptr_rotate<T>(left: usize, mid: *mut T, right: usize) {
+    if T::IS_ZST {
+        return;
+    }
+    // abort early if the rotate is a no-op
+    if (left == 0) || (right == 0) {
+        return;
+    }
+    // `T` is not a zero-sized type, so it's okay to divide by its size.
+    if !cfg!(feature = "optimize_for_size")
+        && cmp::min(left, right) <= mem::size_of::<BufType>() / mem::size_of::<T>()
+    {
+        // SAFETY: guaranteed by the caller
+        unsafe { ptr_rotate_memmove(left, mid, right) };
+    } else if !cfg!(feature = "optimize_for_size")
+        && ((left + right < 24) || (mem::size_of::<T>() > mem::size_of::<[usize; 4]>()))
+    {
+        // SAFETY: guaranteed by the caller
+        unsafe { ptr_rotate_gcd(left, mid, right) }
+    } else {
+        // SAFETY: guaranteed by the caller
+        unsafe { ptr_rotate_swap(left, mid, right) }
+    }
+}
+
+/// Algorithm 1 is used if `min(left, right)` is small enough to fit onto a stack buffer. The
+/// `min(left, right)` elements are copied onto the buffer, `memmove` is applied to the others, and
+/// the ones on the buffer are moved back into the hole on the opposite side of where they
+/// originated.
 ///
-/// # Algorithm
+/// # Safety
 ///
-/// Algorithm 1 is used for small values of `left + right` or for large `T`. The elements are moved
-/// into their final positions one at a time starting at `mid - left` and advancing by `right` steps
-/// modulo `left + right`, such that only one temporary is needed. Eventually, we arrive back at
-/// `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps skipped over
-/// elements. For example:
+/// The specified range must be valid for reading and writing.
+#[inline]
+unsafe fn ptr_rotate_memmove<T>(left: usize, mid: *mut T, right: usize) {
+    // The `[T; 0]` here is to ensure this is appropriately aligned for T
+    let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit();
+    let buf = rawarray.as_mut_ptr() as *mut T;
+    // SAFETY: `mid-left <= mid-left+right < mid+right`
+    let dim = unsafe { mid.sub(left).add(right) };
+    if left <= right {
+        // SAFETY:
+        //
+        // 1) The `if` condition about the sizes ensures `[mid-left; left]` will fit in
+        //    `buf` without overflow and `buf` was created just above and so cannot be
+        //    overlapped with any value of `[mid-left; left]`
+        // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care
+        //    about overlaps here.
+        // 3) The `if` condition about `left <= right` ensures writing `left` elements to
+        //    `dim = mid-left+right` is valid because:
+        //    - `buf` is valid and `left` elements were written in it in 1)
+        //    - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)`
+        unsafe {
+            // 1)
+            ptr::copy_nonoverlapping(mid.sub(left), buf, left);
+            // 2)
+            ptr::copy(mid, mid.sub(left), right);
+            // 3)
+            ptr::copy_nonoverlapping(buf, dim, left);
+        }
+    } else {
+        // SAFETY: same reasoning as above but with `left` and `right` reversed
+        unsafe {
+            ptr::copy_nonoverlapping(mid, buf, right);
+            ptr::copy(mid.sub(left), dim, left);
+            ptr::copy_nonoverlapping(buf, mid.sub(left), right);
+        }
+    }
+}
+
+/// Algorithm 2 is used for small values of `left + right` or for large `T`. The elements
+/// are moved into their final positions one at a time starting at `mid - left` and advancing by
+/// `right` steps modulo `left + right`, such that only one temporary is needed. Eventually, we
+/// arrive back at `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps
+/// skipped over elements. For example:
 /// ```text
 /// left = 10, right = 6
 /// the `^` indicates an element in its final place
@@ -39,17 +109,104 @@ use crate::{cmp, ptr};
 /// `gcd(left + right, right)` value). The end result is that all elements are finalized once and
 /// only once.
 ///
-/// Algorithm 2 is used if `left + right` is large but `min(left, right)` is small enough to
-/// fit onto a stack buffer. The `min(left, right)` elements are copied onto the buffer, `memmove`
-/// is applied to the others, and the ones on the buffer are moved back into the hole on the
-/// opposite side of where they originated.
-///
-/// Algorithms that can be vectorized outperform the above once `left + right` becomes large enough.
-/// Algorithm 1 can be vectorized by chunking and performing many rounds at once, but there are too
+/// Algorithm 2 can be vectorized by chunking and performing many rounds at once, but there are too
 /// few rounds on average until `left + right` is enormous, and the worst case of a single
-/// round is always there. Instead, algorithm 3 utilizes repeated swapping of
-/// `min(left, right)` elements until a smaller rotate problem is left.
+/// round is always there.
+///
+/// # Safety
+///
+/// The specified range must be valid for reading and writing.
+#[inline]
+unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
+    // Algorithm 2
+    // Microbenchmarks indicate that the average performance for random shifts is better all
+    // the way until about `left + right == 32`, but the worst case performance breaks even
+    // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4
+    // `usize`s, this algorithm also outperforms other algorithms.
+    // SAFETY: callers must ensure `mid - left` is valid for reading and writing.
+    let x = unsafe { mid.sub(left) };
+    // beginning of first round
+    // SAFETY: see previous comment.
+    let mut tmp: T = unsafe { x.read() };
+    let mut i = right;
+    // `gcd` can be found before hand by calculating `gcd(left + right, right)`,
+    // but it is faster to do one loop which calculates the gcd as a side effect, then
+    // doing the rest of the chunk
+    let mut gcd = right;
+    // benchmarks reveal that it is faster to swap temporaries all the way through instead
+    // of reading one temporary once, copying backwards, and then writing that temporary at
+    // the very end. This is possibly due to the fact that swapping or replacing temporaries
+    // uses only one memory address in the loop instead of needing to manage two.
+    loop {
+        // [long-safety-expl]
+        // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and
+        // writing.
+        //
+        // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right`
+        // - `i <= left+right-1` is always true
+        //   - if `i < left`, `right` is added so `i < left+right` and on the next
+        //     iteration `left` is removed from `i` so it doesn't go further
+        //   - if `i >= left`, `left` is removed immediately and so it doesn't go further.
+        // - overflows cannot happen for `i` since the function's safety contract ask for
+        //   `mid+right-1 = x+left+right` to be valid for writing
+        // - underflows cannot happen because `i` must be bigger or equal to `left` for
+        //   a subtraction of `left` to happen.
+        //
+        // So `x+i` is valid for reading and writing if the caller respected the contract
+        tmp = unsafe { x.add(i).replace(tmp) };
+        // instead of incrementing `i` and then checking if it is outside the bounds, we
+        // check if `i` will go outside the bounds on the next increment. This prevents
+        // any wrapping of pointers or `usize`.
+        if i >= left {
+            i -= left;
+            if i == 0 {
+                // end of first round
+                // SAFETY: tmp has been read from a valid source and x is valid for writing
+                // according to the caller.
+                unsafe { x.write(tmp) };
+                break;
+            }
+            // this conditional must be here if `left + right >= 15`
+            if i < gcd {
+                gcd = i;
+            }
+        } else {
+            i += right;
+        }
+    }
+    // finish the chunk with more rounds
+    for start in 1..gcd {
+        // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for
+        // reading and writing as per the function's safety contract, see [long-safety-expl]
+        // above
+        tmp = unsafe { x.add(start).read() };
+        // [safety-expl-addition]
+        //
+        // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the
+        // greatest common divisor of `(left+right, right)` means that `left = right` so
+        // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing
+        // according to the function's safety contract.
+        i = start + right;
+        loop {
+            // SAFETY: see [long-safety-expl] and [safety-expl-addition]
+            tmp = unsafe { x.add(i).replace(tmp) };
+            if i >= left {
+                i -= left;
+                if i == start {
+                    // SAFETY: see [long-safety-expl] and [safety-expl-addition]
+                    unsafe { x.add(start).write(tmp) };
+                    break;
+                }
+            } else {
+                i += right;
+            }
+        }
+    }
+}
+
+/// Algorithm 3 utilizes repeated swapping of `min(left, right)` elements.
 ///
+/// ///
 /// ```text
 /// left = 11, right = 4
 /// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3]
@@ -60,144 +217,14 @@ use crate::{cmp, ptr};
 /// we cannot swap any more, but a smaller rotation problem is left to solve
 /// ```
 /// when `left < right` the swapping happens from the left instead.
-pub(super) unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
-    type BufType = [usize; 32];
-    if T::IS_ZST {
-        return;
-    }
+///
+/// # Safety
+///
+/// The specified range must be valid for reading and writing.
+#[inline]
+unsafe fn ptr_rotate_swap<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
     loop {
-        // N.B. the below algorithms can fail if these cases are not checked
-        if (right == 0) || (left == 0) {
-            return;
-        }
-        if !cfg!(feature = "optimize_for_size")
-            && ((left + right < 24) || (mem::size_of::<T>() > mem::size_of::<[usize; 4]>()))
-        {
-            // Algorithm 1
-            // Microbenchmarks indicate that the average performance for random shifts is better all
-            // the way until about `left + right == 32`, but the worst case performance breaks even
-            // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4
-            // `usize`s, this algorithm also outperforms other algorithms.
-            // SAFETY: callers must ensure `mid - left` is valid for reading and writing.
-            let x = unsafe { mid.sub(left) };
-            // beginning of first round
-            // SAFETY: see previous comment.
-            let mut tmp: T = unsafe { x.read() };
-            let mut i = right;
-            // `gcd` can be found before hand by calculating `gcd(left + right, right)`,
-            // but it is faster to do one loop which calculates the gcd as a side effect, then
-            // doing the rest of the chunk
-            let mut gcd = right;
-            // benchmarks reveal that it is faster to swap temporaries all the way through instead
-            // of reading one temporary once, copying backwards, and then writing that temporary at
-            // the very end. This is possibly due to the fact that swapping or replacing temporaries
-            // uses only one memory address in the loop instead of needing to manage two.
-            loop {
-                // [long-safety-expl]
-                // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and
-                // writing.
-                //
-                // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right`
-                // - `i <= left+right-1` is always true
-                //   - if `i < left`, `right` is added so `i < left+right` and on the next
-                //     iteration `left` is removed from `i` so it doesn't go further
-                //   - if `i >= left`, `left` is removed immediately and so it doesn't go further.
-                // - overflows cannot happen for `i` since the function's safety contract ask for
-                //   `mid+right-1 = x+left+right` to be valid for writing
-                // - underflows cannot happen because `i` must be bigger or equal to `left` for
-                //   a subtraction of `left` to happen.
-                //
-                // So `x+i` is valid for reading and writing if the caller respected the contract
-                tmp = unsafe { x.add(i).replace(tmp) };
-                // instead of incrementing `i` and then checking if it is outside the bounds, we
-                // check if `i` will go outside the bounds on the next increment. This prevents
-                // any wrapping of pointers or `usize`.
-                if i >= left {
-                    i -= left;
-                    if i == 0 {
-                        // end of first round
-                        // SAFETY: tmp has been read from a valid source and x is valid for writing
-                        // according to the caller.
-                        unsafe { x.write(tmp) };
-                        break;
-                    }
-                    // this conditional must be here if `left + right >= 15`
-                    if i < gcd {
-                        gcd = i;
-                    }
-                } else {
-                    i += right;
-                }
-            }
-            // finish the chunk with more rounds
-            for start in 1..gcd {
-                // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for
-                // reading and writing as per the function's safety contract, see [long-safety-expl]
-                // above
-                tmp = unsafe { x.add(start).read() };
-                // [safety-expl-addition]
-                //
-                // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the
-                // greatest common divisor of `(left+right, right)` means that `left = right` so
-                // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing
-                // according to the function's safety contract.
-                i = start + right;
-                loop {
-                    // SAFETY: see [long-safety-expl] and [safety-expl-addition]
-                    tmp = unsafe { x.add(i).replace(tmp) };
-                    if i >= left {
-                        i -= left;
-                        if i == start {
-                            // SAFETY: see [long-safety-expl] and [safety-expl-addition]
-                            unsafe { x.add(start).write(tmp) };
-                            break;
-                        }
-                    } else {
-                        i += right;
-                    }
-                }
-            }
-            return;
-        // `T` is not a zero-sized type, so it's okay to divide by its size.
-        } else if !cfg!(feature = "optimize_for_size")
-            && cmp::min(left, right) <= mem::size_of::<BufType>() / mem::size_of::<T>()
-        {
-            // Algorithm 2
-            // The `[T; 0]` here is to ensure this is appropriately aligned for T
-            let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit();
-            let buf = rawarray.as_mut_ptr() as *mut T;
-            // SAFETY: `mid-left <= mid-left+right < mid+right`
-            let dim = unsafe { mid.sub(left).add(right) };
-            if left <= right {
-                // SAFETY:
-                //
-                // 1) The `else if` condition about the sizes ensures `[mid-left; left]` will fit in
-                //    `buf` without overflow and `buf` was created just above and so cannot be
-                //    overlapped with any value of `[mid-left; left]`
-                // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care
-                //    about overlaps here.
-                // 3) The `if` condition about `left <= right` ensures writing `left` elements to
-                //    `dim = mid-left+right` is valid because:
-                //    - `buf` is valid and `left` elements were written in it in 1)
-                //    - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)`
-                unsafe {
-                    // 1)
-                    ptr::copy_nonoverlapping(mid.sub(left), buf, left);
-                    // 2)
-                    ptr::copy(mid, mid.sub(left), right);
-                    // 3)
-                    ptr::copy_nonoverlapping(buf, dim, left);
-                }
-            } else {
-                // SAFETY: same reasoning as above but with `left` and `right` reversed
-                unsafe {
-                    ptr::copy_nonoverlapping(mid, buf, right);
-                    ptr::copy(mid.sub(left), dim, left);
-                    ptr::copy_nonoverlapping(buf, mid.sub(left), right);
-                }
-            }
-            return;
-        } else if left >= right {
+        if left >= right {
             // Algorithm 3
             // There is an alternate way of swapping that involves finding where the last swap
             // of this algorithm would be, and swapping using that last chunk instead of swapping
@@ -233,5 +260,8 @@ pub(super) unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right:
                 }
             }
         }
+        if (right == 0) || (left == 0) {
+            return;
+        }
     }
 }
diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs
index 644e75a4581..cf1df1e91a5 100644
--- a/library/core/src/slice/sort/stable/drift.rs
+++ b/library/core/src/slice/sort/stable/drift.rs
@@ -10,8 +10,8 @@ use crate::{cmp, intrinsics};
 
 /// Sorts `v` based on comparison function `is_less`. If `eager_sort` is true,
 /// it will only do small-sorts and physical merges, ensuring O(N * log(N))
-/// worst-case complexity. `scratch.len()` must be at least `max(v.len() / 2,
-/// MIN_SMALL_SORT_SCRATCH_LEN)` otherwise the implementation may abort.
+/// worst-case complexity. `scratch.len()` must be at least
+/// `max(v.len() - v.len() / 2, SMALL_SORT_GENERAL_SCRATCH_LEN)` otherwise the implementation may abort.
 /// Fully ascending and descending inputs will be sorted with exactly N - 1
 /// comparisons.
 ///
diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs
index 7adcc83b818..3ff2e71fd05 100644
--- a/library/core/src/slice/sort/stable/mod.rs
+++ b/library/core/src/slice/sort/stable/mod.rs
@@ -41,6 +41,8 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less
 
     cfg_if! {
         if #[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] {
+            // Unlike driftsort, mergesort only requires len / 2,
+            // not len - len / 2.
             let alloc_len = len / 2;
 
             cfg_if! {
@@ -91,16 +93,26 @@ fn driftsort_main<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], i
     // By allocating n elements of memory we can ensure the entire input can
     // be sorted using stable quicksort, which allows better performance on
     // random and low-cardinality distributions. However, we still want to
-    // reduce our memory usage to n / 2 for large inputs. We do this by scaling
-    // our allocation as max(n / 2, min(n, 8MB)), ensuring we scale like n for
-    // small inputs and n / 2 for large inputs, without a sudden drop off. We
-    // also need to ensure our alloc >= MIN_SMALL_SORT_SCRATCH_LEN, as the
+    // reduce our memory usage to n - n / 2 for large inputs. We do this by scaling
+    // our allocation as max(n - n / 2, min(n, 8MB)), ensuring we scale like n for
+    // small inputs and n - n / 2 for large inputs, without a sudden drop off. We
+    // also need to ensure our alloc >= SMALL_SORT_GENERAL_SCRATCH_LEN, as the
     // small-sort always needs this much memory.
+    //
+    // driftsort will produce unsorted runs of up to min_good_run_len, which
+    // is at most len - len / 2.
+    // Unsorted runs need to be processed by quicksort, which requires as much
+    // scratch space as the run length, therefore the scratch space must be at
+    // least len - len / 2.
+    // If min_good_run_len is ever modified, this code must be updated to allocate
+    // the correct scratch size for it.
     const MAX_FULL_ALLOC_BYTES: usize = 8_000_000; // 8MB
     let max_full_alloc = MAX_FULL_ALLOC_BYTES / mem::size_of::<T>();
     let len = v.len();
-    let alloc_len =
-        cmp::max(cmp::max(len / 2, cmp::min(len, max_full_alloc)), SMALL_SORT_GENERAL_SCRATCH_LEN);
+    let alloc_len = cmp::max(
+        cmp::max(len - len / 2, cmp::min(len, max_full_alloc)),
+        SMALL_SORT_GENERAL_SCRATCH_LEN,
+    );
 
     // For small inputs 4KiB of stack storage suffices, which allows us to avoid
     // calling the (de-)allocator. Benchmarks showed this was quite beneficial.
diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs
index 0c8308bfce0..630c6ff9077 100644
--- a/library/core/src/slice/sort/stable/quicksort.rs
+++ b/library/core/src/slice/sort/stable/quicksort.rs
@@ -7,6 +7,8 @@ use crate::slice::sort::shared::smallsort::StableSmallSortTypeImpl;
 use crate::{intrinsics, ptr};
 
 /// Sorts `v` recursively using quicksort.
+/// `scratch.len()` must be at least `max(v.len() - v.len() / 2, SMALL_SORT_GENERAL_SCRATCH_LEN)`
+/// otherwise the implementation may abort.
 ///
 /// `limit` when initialized with `c*log(v.len())` for some c ensures we do not
 /// overflow the stack or go quadratic.
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 8a473b398bb..39fa6c1a25f 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -1108,7 +1108,8 @@ impl str {
         LinesAny(self.lines())
     }
 
-    /// Returns an iterator of `u16` over the string encoded as UTF-16.
+    /// Returns an iterator of `u16` over the string encoded
+    /// as native endian UTF-16 (without byte-order mark).
     ///
     /// # Examples
     ///
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 0061e33f986..73180bde54a 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -716,6 +716,12 @@ impl AtomicBool {
     /// AcqRel   | AcqRel  | Acquire
     /// SeqCst   | SeqCst  | SeqCst
     ///
+    /// `compare_and_swap` and `compare_exchange` also differ in their return type. You can use
+    /// `compare_exchange(...).unwrap_or_else(|x| x)` to recover the behavior of `compare_and_swap`,
+    /// but in most cases it is more idiomatic to check whether the return value is `Ok` or `Err`
+    /// rather than to infer success vs failure based on the value that was read.
+    ///
+    /// During migration, consider whether it makes sense to use `compare_exchange_weak` instead.
     /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds,
     /// which allows the compiler to generate better assembly code when the compare and swap
     /// is used in a loop.
@@ -1651,6 +1657,12 @@ impl<T> AtomicPtr<T> {
     /// AcqRel   | AcqRel  | Acquire
     /// SeqCst   | SeqCst  | SeqCst
     ///
+    /// `compare_and_swap` and `compare_exchange` also differ in their return type. You can use
+    /// `compare_exchange(...).unwrap_or_else(|x| x)` to recover the behavior of `compare_and_swap`,
+    /// but in most cases it is more idiomatic to check whether the return value is `Ok` or `Err`
+    /// rather than to infer success vs failure based on the value that was read.
+    ///
+    /// During migration, consider whether it makes sense to use `compare_exchange_weak` instead.
     /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds,
     /// which allows the compiler to generate better assembly code when the compare and swap
     /// is used in a loop.
@@ -2771,6 +2783,12 @@ macro_rules! atomic_int {
             /// AcqRel   | AcqRel  | Acquire
             /// SeqCst   | SeqCst  | SeqCst
             ///
+            /// `compare_and_swap` and `compare_exchange` also differ in their return type. You can use
+            /// `compare_exchange(...).unwrap_or_else(|x| x)` to recover the behavior of `compare_and_swap`,
+            /// but in most cases it is more idiomatic to check whether the return value is `Ok` or `Err`
+            /// rather than to infer success vs failure based on the value that was read.
+            ///
+            /// During migration, consider whether it makes sense to use `compare_exchange_weak` instead.
             /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds,
             /// which allows the compiler to generate better assembly code when the compare and swap
             /// is used in a loop.
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 0607d508a48..7fe72862608 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -14,7 +14,6 @@
 #![feature(bstr)]
 #![feature(cell_update)]
 #![feature(clone_to_uninit)]
-#![feature(const_black_box)]
 #![feature(const_eval_select)]
 #![feature(const_swap_nonoverlapping)]
 #![feature(const_trait_impl)]
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 1f8aac48a9a..a5b0111adfb 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -629,9 +629,9 @@ impl File {
     /// This acquires an exclusive advisory lock; no other file handle to this file may acquire
     /// another lock.
     ///
-    /// If this file handle, or a clone of it, already holds an advisory lock the exact behavior is
-    /// unspecified and platform dependent, including the possibility that it will deadlock.
-    /// However, if this method returns, then an exclusive lock is held.
+    /// If this file handle/descriptor, or a clone of it, already holds an advisory lock the exact
+    /// behavior is unspecified and platform dependent, including the possibility that it will
+    /// deadlock. However, if this method returns, then an exclusive lock is held.
     ///
     /// If the file not open for writing, it is unspecified whether this function returns an error.
     ///
@@ -639,6 +639,9 @@ impl File {
     /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
     /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
     ///
+    /// The lock will be released when this file (along with any other file descriptors/handles
+    /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
+    ///
     /// # Platform-specific behavior
     ///
     /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` flag,
@@ -671,19 +674,22 @@ impl File {
         self.inner.lock()
     }
 
-    /// Acquire a shared advisory lock on the file. Blocks until the lock can be acquired.
+    /// Acquire a shared (non-exclusive) advisory lock on the file. Blocks until the lock can be acquired.
     ///
     /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but
-    /// none may hold an exclusive lock.
+    /// none may hold an exclusive lock at the same time.
     ///
-    /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
-    /// unspecified and platform dependent, including the possibility that it will deadlock.
-    /// However, if this method returns, then a shared lock is held.
+    /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact
+    /// behavior is unspecified and platform dependent, including the possibility that it will
+    /// deadlock. However, if this method returns, then a shared lock is held.
     ///
     /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`],
     /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
     /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
     ///
+    /// The lock will be released when this file (along with any other file descriptors/handles
+    /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
+    ///
     /// # Platform-specific behavior
     ///
     /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` flag,
@@ -716,14 +722,18 @@ impl File {
         self.inner.lock_shared()
     }
 
-    /// Acquire an exclusive advisory lock on the file. Returns `Ok(false)` if the file is locked.
+    /// Try to acquire an exclusive advisory lock on the file.
+    ///
+    /// Returns `Ok(false)` if a different lock is already held on this file (via another
+    /// handle/descriptor).
     ///
     /// This acquires an exclusive advisory lock; no other file handle to this file may acquire
     /// another lock.
     ///
-    /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
-    /// unspecified and platform dependent, including the possibility that it will deadlock.
-    /// However, if this method returns, then an exclusive lock is held.
+    /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact
+    /// behavior is unspecified and platform dependent, including the possibility that it will
+    /// deadlock. However, if this method returns `Ok(true)`, then it has acquired an exclusive
+    /// lock.
     ///
     /// If the file not open for writing, it is unspecified whether this function returns an error.
     ///
@@ -731,6 +741,9 @@ impl File {
     /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
     /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
     ///
+    /// The lock will be released when this file (along with any other file descriptors/handles
+    /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
+    ///
     /// # Platform-specific behavior
     ///
     /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` and
@@ -764,20 +777,25 @@ impl File {
         self.inner.try_lock()
     }
 
-    /// Acquire a shared advisory lock on the file.
-    /// Returns `Ok(false)` if the file is exclusively locked.
+    /// Try to acquire a shared (non-exclusive) advisory lock on the file.
+    ///
+    /// Returns `Ok(false)` if an exclusive lock is already held on this file (via another
+    /// handle/descriptor).
     ///
     /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but
-    /// none may hold an exclusive lock.
+    /// none may hold an exclusive lock at the same time.
     ///
     /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
     /// unspecified and platform dependent, including the possibility that it will deadlock.
-    /// However, if this method returns, then a shared lock is held.
+    /// However, if this method returns `Ok(true)`, then it has acquired a shared lock.
     ///
     /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`],
     /// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`]
     /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
     ///
+    /// The lock will be released when this file (along with any other file descriptors/handles
+    /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
+    ///
     /// # Platform-specific behavior
     ///
     /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` and
@@ -813,7 +831,12 @@ impl File {
 
     /// Release all locks on the file.
     ///
-    /// All remaining locks are released when the file handle, and all clones of it, are dropped.
+    /// All locks are released when the file (along with any other file descriptors/handles
+    /// duplicated or inherited from it) is closed. This method allows releasing locks without
+    /// closing the file.
+    ///
+    /// If no lock is currently held via this file descriptor/handle, this method may return an
+    /// error, or may return successfully without taking any action.
     ///
     /// # Platform-specific behavior
     ///
diff --git a/library/std/src/io/pipe/tests.rs b/library/std/src/io/pipe/tests.rs
index c1f3f192ca2..f113b157459 100644
--- a/library/std/src/io/pipe/tests.rs
+++ b/library/std/src/io/pipe/tests.rs
@@ -1,7 +1,7 @@
 use crate::io::{Read, Write, pipe};
 
 #[test]
-#[cfg(all(windows, unix, not(miri)))]
+#[cfg(all(any(unix, windows), not(miri)))]
 fn pipe_creation_clone_and_rw() {
     let (rx, tx) = pipe().unwrap();
 
diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs
index 4ec328208f0..14e6c2715df 100644
--- a/library/std/src/prelude/mod.rs
+++ b/library/std/src/prelude/mod.rs
@@ -120,16 +120,6 @@ mod common;
 pub mod v1 {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::common::*;
-
-    // Do not `doc(inline)` these `doc(hidden)` items.
-    #[unstable(
-        feature = "rustc_encodable_decodable",
-        issue = "none",
-        soft,
-        reason = "derive macro for `rustc-serialize`; should not be used in new code"
-    )]
-    #[allow(deprecated)]
-    pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
 }
 
 /// The 2015 version of the prelude of The Rust Standard Library.
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index e0dd2e14817..fd0fd1cb755 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -2318,14 +2318,10 @@ pub fn exit(code: i32) -> ! {
 /// Terminates the process in an abnormal fashion.
 ///
 /// The function will never return and will immediately terminate the current
-/// process in a platform specific "abnormal" manner.
-///
-/// Note that because this function never returns, and that it terminates the
-/// process, no destructors on the current stack or any other thread's stack
-/// will be run.
-///
-/// Rust IO buffers (eg, from `BufWriter`) will not be flushed.
-/// Likewise, C stdio buffers will (on most platforms) not be flushed.
+/// process in a platform specific "abnormal" manner. As a consequence,
+/// no destructors on the current stack or any other thread's stack
+/// will be run, Rust IO buffers (eg, from `BufWriter`) will not be flushed,
+/// and C stdio buffers will (on most platforms) not be flushed.
 ///
 /// This is in contrast to the default behavior of [`panic!`] which unwinds
 /// the current thread's stack and calls all destructors.
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index 49f2dafd8fd..6fc0abbed9e 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -174,8 +174,6 @@ impl<T> OnceLock<T> {
     ///
     /// Waiting for a computation on another thread to finish:
     /// ```rust
-    /// #![feature(once_wait)]
-    ///
     /// use std::thread;
     /// use std::sync::OnceLock;
     ///
@@ -189,7 +187,7 @@ impl<T> OnceLock<T> {
     /// })
     /// ```
     #[inline]
-    #[unstable(feature = "once_wait", issue = "127527")]
+    #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")]
     pub fn wait(&self) -> &T {
         self.once.wait_force();
 
diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs
index 01ef71a187f..fb43ada6375 100644
--- a/library/std/src/sync/poison/mutex.rs
+++ b/library/std/src/sync/poison/mutex.rs
@@ -181,10 +181,29 @@ pub struct Mutex<T: ?Sized> {
     data: UnsafeCell<T>,
 }
 
-// these are the only places where `T: Send` matters; all other
-// functionality works fine on a single thread.
+/// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire
+/// the owned `T` from the `Mutex` via [`into_inner`].
+///
+/// [`into_inner`]: Mutex::into_inner
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
+
+/// `T` must be `Send` for [`Mutex`] to be `Sync`.
+/// This ensures that the protected data can be accessed safely from multiple threads
+/// without causing data races or other unsafe behavior.
+///
+/// [`Mutex<T>`] provides mutable access to `T` to one thread at a time. However, it's essential
+/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in
+/// this manner. For instance, consider [`Rc`], a non-atomic reference counted smart pointer,
+/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap
+/// allocation with a non-atomic reference count. If we were to use `Mutex<Rc<_>>`, it would
+/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable
+/// to potential data races.
+///
+/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available
+/// to one thread at a time if `T` is not `Sync`.
+///
+/// [`Rc`]: crate::rc::Rc
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
 
@@ -211,8 +230,17 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> {
     poison: poison::Guard,
 }
 
+/// A [`MutexGuard`] is not `Send` to maximize platform portablity.
+///
+/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
+/// release mutex locks on the same thread they were acquired.
+/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from
+/// another thread.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
+
+/// `T` must be `Sync` for a [`MutexGuard<T>`] to be `Sync`
+/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`).
 #[stable(feature = "mutexguard", since = "1.19.0")]
 unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
 
diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs
index 27db4b634fb..528b11ca0c1 100644
--- a/library/std/src/sync/poison/once.rs
+++ b/library/std/src/sync/poison/once.rs
@@ -269,8 +269,6 @@ impl Once {
     /// # Example
     ///
     /// ```rust
-    /// #![feature(once_wait)]
-    ///
     /// use std::sync::Once;
     /// use std::thread;
     ///
@@ -289,7 +287,7 @@ impl Once {
     /// If this [`Once`] has been poisoned because an initialization closure has
     /// panicked, this method will also panic. Use [`wait_force`](Self::wait_force)
     /// if this behavior is not desired.
-    #[unstable(feature = "once_wait", issue = "127527")]
+    #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")]
     pub fn wait(&self) {
         if !self.inner.is_completed() {
             self.inner.wait(false);
@@ -298,7 +296,7 @@ impl Once {
 
     /// Blocks the current thread until initialization has completed, ignoring
     /// poisoning.
-    #[unstable(feature = "once_wait", issue = "127527")]
+    #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")]
     pub fn wait_force(&self) {
         if !self.inner.is_completed() {
             self.inner.wait(true);
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index 7504a0f7ad7..dccc137d6f5 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -14,10 +14,12 @@ use r_efi::protocols::{device_path, device_path_to_text, shell};
 
 use crate::ffi::{OsStr, OsString};
 use crate::io::{self, const_error};
+use crate::marker::PhantomData;
 use crate::mem::{MaybeUninit, size_of};
 use crate::os::uefi::env::boot_services;
 use crate::os::uefi::ffi::{OsStrExt, OsStringExt};
 use crate::os::uefi::{self};
+use crate::path::Path;
 use crate::ptr::NonNull;
 use crate::slice;
 use crate::sync::atomic::{AtomicPtr, Ordering};
@@ -278,6 +280,10 @@ impl OwnedDevicePath {
     pub(crate) const fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol {
         self.0.as_ptr()
     }
+
+    pub(crate) const fn borrow<'a>(&'a self) -> BorrowedDevicePath<'a> {
+        BorrowedDevicePath::new(self.0)
+    }
 }
 
 impl Drop for OwnedDevicePath {
@@ -293,13 +299,37 @@ impl Drop for OwnedDevicePath {
 
 impl crate::fmt::Debug for OwnedDevicePath {
     fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
-        match device_path_to_text(self.0) {
+        match self.borrow().to_text() {
             Ok(p) => p.fmt(f),
             Err(_) => f.debug_struct("OwnedDevicePath").finish_non_exhaustive(),
         }
     }
 }
 
+pub(crate) struct BorrowedDevicePath<'a> {
+    protocol: NonNull<r_efi::protocols::device_path::Protocol>,
+    phantom: PhantomData<&'a r_efi::protocols::device_path::Protocol>,
+}
+
+impl<'a> BorrowedDevicePath<'a> {
+    pub(crate) const fn new(protocol: NonNull<r_efi::protocols::device_path::Protocol>) -> Self {
+        Self { protocol, phantom: PhantomData }
+    }
+
+    pub(crate) fn to_text(&self) -> io::Result<OsString> {
+        device_path_to_text(self.protocol)
+    }
+}
+
+impl<'a> crate::fmt::Debug for BorrowedDevicePath<'a> {
+    fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
+        match self.to_text() {
+            Ok(p) => p.fmt(f),
+            Err(_) => f.debug_struct("BorrowedDevicePath").finish_non_exhaustive(),
+        }
+    }
+}
+
 pub(crate) struct OwnedProtocol<T> {
     guid: r_efi::efi::Guid,
     handle: NonNull<crate::ffi::c_void>,
@@ -452,3 +482,21 @@ pub(crate) fn open_shell() -> Option<NonNull<shell::Protocol>> {
 
     None
 }
+
+/// Get device path protocol associated with shell mapping.
+///
+/// returns None in case no such mapping is exists
+pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result<BorrowedDevicePath<'static>> {
+    let shell =
+        open_shell().ok_or(io::const_error!(io::ErrorKind::NotFound, "UEFI Shell not found"))?;
+    let mut path = os_string_to_raw(map.as_os_str())
+        .ok_or(io::const_error!(io::ErrorKind::InvalidFilename, "Invalid UEFI shell mapping"))?;
+
+    // The Device Path Protocol pointer returned by UEFI shell is owned by the shell and is not
+    // freed throughout it's lifetime. So it has a 'static lifetime.
+    let protocol = unsafe { ((*shell.as_ptr()).get_device_path_from_map)(path.as_mut_ptr()) };
+    let protocol = NonNull::new(protocol)
+        .ok_or(io::const_error!(io::ErrorKind::NotFound, "UEFI Shell mapping not found"))?;
+
+    Ok(BorrowedDevicePath::new(protocol))
+}
diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
index 1a0754134df..3077a72eac6 100644
--- a/library/std/src/sys/pal/uefi/process.rs
+++ b/library/std/src/sys/pal/uefi/process.rs
@@ -460,7 +460,7 @@ mod uefi_command_internal {
                 helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
 
             let len = args.len();
-            let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap();
+            let args_size: u32 = (len * crate::mem::size_of::<u16>()).try_into().unwrap();
             let ptr = Box::into_raw(args).as_mut_ptr();
 
             unsafe {
@@ -706,9 +706,10 @@ mod uefi_command_internal {
         res.push(QUOTE);
         res.extend(prog.encode_wide());
         res.push(QUOTE);
-        res.push(SPACE);
 
         for arg in args {
+            res.push(SPACE);
+
             // Wrap the argument in quotes to be treat as single arg
             res.push(QUOTE);
             for c in arg.encode_wide() {
@@ -719,8 +720,6 @@ mod uefi_command_internal {
                 res.push(c);
             }
             res.push(QUOTE);
-
-            res.push(SPACE);
         }
 
         res.into_boxed_slice()
diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs
index 24a94ec7828..1fa4e80d678 100644
--- a/library/std/src/sys/path/mod.rs
+++ b/library/std/src/sys/path/mod.rs
@@ -5,12 +5,12 @@ cfg_if::cfg_if! {
     } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
         mod sgx;
         pub use sgx::*;
-    } else if #[cfg(any(
-        target_os = "uefi",
-        target_os = "solid_asp3",
-    ))] {
+    } else if #[cfg(target_os = "solid_asp3")] {
         mod unsupported_backslash;
         pub use unsupported_backslash::*;
+    } else if #[cfg(target_os = "uefi")] {
+        mod uefi;
+        pub use uefi::*;
     } else {
         mod unix;
         pub use unix::*;
diff --git a/library/std/src/sys/path/uefi.rs b/library/std/src/sys/path/uefi.rs
new file mode 100644
index 00000000000..a3f4a3bfe1b
--- /dev/null
+++ b/library/std/src/sys/path/uefi.rs
@@ -0,0 +1,105 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
+use crate::ffi::OsStr;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::{helpers, unsupported_err};
+
+const FORWARD_SLASH: u8 = b'/';
+const COLON: u8 = b':';
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'\\'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'\\'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+    None
+}
+
+pub const MAIN_SEP_STR: &str = "\\";
+pub const MAIN_SEP: char = '\\';
+
+/// UEFI paths can be of 4 types:
+///
+/// 1. Absolute Shell Path: Uses shell mappings (eg: `FS0:`). Does not exist if UEFI shell not present.
+///    It can be identified with `:`.
+///    Eg: FS0:\abc\run.efi
+///
+/// 2. Absolute Device Path: this is what we want
+///    It can be identified with `/`.
+///    Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi
+///
+/// 3: Relative root: path relative to the current volume.
+///    It will start with `\`.
+///    Eg: \abc\run.efi
+///
+/// 4: Relative
+///    Eg: run.efi
+///
+/// The algorithm is mostly taken from edk2 UEFI shell implementation and is
+/// somewhat simple. Check for the path type in order.
+///
+/// The volume mapping in Absolute Shell Path (not the rest of the path) can be converted to Device
+/// Path Protocol using `EFI_SHELL->GetDevicePathFromMap`. The rest of the path (Relative root
+/// path), can just be appended to the remaining path.
+///
+/// For Relative root, we get the current volume (either in Shell Mapping, or Device Path Protocol
+/// form) and join it with the relative root path. We then recurse the function to resolve the Shell
+/// Mapping if present.
+///
+/// For Relative paths, we use the current working directory to construct
+/// the new path and recurse the function to resolve the Shell mapping if present.
+///
+/// Finally, at the end, we get the 2nd form, i.e. Absolute Device Path, which can be used in the
+/// normal UEFI APIs such as file, process, etc.
+/// Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+    // Absolute Shell Path
+    if path.as_os_str().as_encoded_bytes().contains(&COLON) {
+        let mut path_components = path.components();
+        // Since path is not empty, it has at least one Component
+        let prefix = path_components.next().unwrap();
+
+        let dev_path = helpers::get_device_path_from_map(prefix.as_ref())?;
+        let mut dev_path_text = dev_path.to_text().map_err(|_| unsupported_err())?;
+
+        // UEFI Shell does not seem to end device path with `/`
+        if *dev_path_text.as_encoded_bytes().last().unwrap() != FORWARD_SLASH {
+            dev_path_text.push("/");
+        }
+
+        let mut ans = PathBuf::from(dev_path_text);
+        ans.push(path_components);
+
+        return Ok(ans);
+    }
+
+    // Absolute Device Path
+    if path.as_os_str().as_encoded_bytes().contains(&FORWARD_SLASH) {
+        return Ok(path.to_path_buf());
+    }
+
+    // cur_dir() always returns something
+    let cur_dir = crate::env::current_dir().unwrap();
+    let mut path_components = path.components();
+
+    // Relative Root
+    if path_components.next().unwrap() == crate::path::Component::RootDir {
+        let mut ans = PathBuf::new();
+        ans.push(cur_dir.components().next().unwrap());
+        ans.push(path_components);
+        return absolute(&ans);
+    }
+
+    absolute(&cur_dir.join(path))
+}
+
+pub(crate) fn is_absolute(path: &Path) -> bool {
+    let temp = path.as_os_str().as_encoded_bytes();
+    temp.contains(&COLON) || temp.contains(&FORWARD_SLASH)
+}
diff --git a/license-metadata.json b/license-metadata.json
index 09cc3693565..4cf9bea2861 100644
--- a/license-metadata.json
+++ b/license-metadata.json
@@ -113,8 +113,12 @@
               {
                 "directories": [],
                 "files": [
+                  "FiraMono-Medium.woff2",
+                  "FiraMono-Regular.woff2",
+                  "FiraSans-Italic.woff2",
                   "FiraSans-LICENSE.txt",
                   "FiraSans-Medium.woff2",
+                  "FiraSans-MediumItalic.woff2",
                   "FiraSans-Regular.woff2"
                 ],
                 "license": {
@@ -266,4 +270,4 @@
     ],
     "type": "root"
   }
-}
\ No newline at end of file
+}
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index fd9bf47234c..f447d186a52 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1049,9 +1049,12 @@ pub fn rustc_cargo(
     // <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Internal.20lint.20for.20raw.20.60print!.60.20and.20.60println!.60.3F>.
     cargo.rustflag("-Zon-broken-pipe=kill");
 
-    if builder.config.llvm_enzyme {
-        cargo.rustflag("-l").rustflag("Enzyme-19");
-    }
+    // We temporarily disable linking here as part of some refactoring.
+    // This way, people can manually use -Z llvm-plugins and -C passes=enzyme for now.
+    // In a follow-up PR, we will re-enable linking here and load the pass for them.
+    //if builder.config.llvm_enzyme {
+    //    cargo.rustflag("-l").rustflag("Enzyme-19");
+    //}
 
     // Building with protected visibility reduces the number of dynamic relocations needed, giving
     // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 5e250d18ce6..825e5452f0e 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -86,6 +86,7 @@ impl Step for CrateBootstrap {
             SourceType::InTree,
             &[],
         );
+
         let crate_name = path.rsplit_once('/').unwrap().1;
         run_cargo_test(cargo, &[], &[], crate_name, crate_name, bootstrap_host, builder);
     }
@@ -3106,6 +3107,8 @@ impl Step for Bootstrap {
             &[],
         );
 
+        cargo.release_build(false);
+
         cargo
             .rustflag("-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 1b413dcb07e..f6a03a386d1 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -88,12 +88,14 @@ impl HostFlags {
 #[derive(Debug)]
 pub struct Cargo {
     command: BootstrapCommand,
+    args: Vec<OsString>,
     compiler: Compiler,
     target: TargetSelection,
     rustflags: Rustflags,
     rustdocflags: Rustflags,
     hostflags: HostFlags,
     allow_features: String,
+    release_build: bool,
 }
 
 impl Cargo {
@@ -121,6 +123,10 @@ impl Cargo {
         cargo
     }
 
+    pub fn release_build(&mut self, release_build: bool) {
+        self.release_build = release_build;
+    }
+
     pub fn compiler(&self) -> Compiler {
         self.compiler
     }
@@ -153,7 +159,7 @@ impl Cargo {
     }
 
     pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Cargo {
-        self.command.arg(arg.as_ref());
+        self.args.push(arg.as_ref().into());
         self
     }
 
@@ -342,6 +348,12 @@ impl Cargo {
 
 impl From<Cargo> for BootstrapCommand {
     fn from(mut cargo: Cargo) -> BootstrapCommand {
+        if cargo.release_build {
+            cargo.args.insert(0, "--release".into());
+        }
+
+        cargo.command.args(cargo.args);
+
         let rustflags = &cargo.rustflags.0;
         if !rustflags.is_empty() {
             cargo.command.env("RUSTFLAGS", rustflags);
@@ -360,6 +372,7 @@ impl From<Cargo> for BootstrapCommand {
         if !cargo.allow_features.is_empty() {
             cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features);
         }
+
         cargo.command
     }
 }
@@ -429,13 +442,6 @@ impl Builder<'_> {
             assert_eq!(target, compiler.host);
         }
 
-        if self.config.rust_optimize.is_release() &&
-        // cargo bench/install do not accept `--release` and miri doesn't want it
-        !matches!(cmd_kind, Kind::Bench | Kind::Install | Kind::Miri | Kind::MiriSetup | Kind::MiriTest)
-        {
-            cargo.arg("--release");
-        }
-
         // Remove make-related flags to ensure Cargo can correctly set things up
         cargo.env_remove("MAKEFLAGS");
         cargo.env_remove("MFLAGS");
@@ -1218,14 +1224,20 @@ impl Builder<'_> {
             rustflags.arg("-Zmir_strip_debuginfo=locals-in-tiny-functions");
         }
 
+        let release_build = self.config.rust_optimize.is_release() &&
+            // cargo bench/install do not accept `--release` and miri doesn't want it
+            !matches!(cmd_kind, Kind::Bench | Kind::Install | Kind::Miri | Kind::MiriSetup | Kind::MiriTest);
+
         Cargo {
             command: cargo,
+            args: vec![],
             compiler,
             target,
             rustflags,
             rustdocflags,
             hostflags,
             allow_features,
+            release_build,
         }
     }
 }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 98490118f7d..781d0e602c3 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -700,7 +700,7 @@ trait Merge {
 impl Merge for TomlConfig {
     fn merge(
         &mut self,
-        TomlConfig { build, install, llvm, rust, dist, target, profile: _, change_id }: Self,
+        TomlConfig { build, install, llvm, rust, dist, target, profile, change_id }: Self,
         replace: ReplaceOpt,
     ) {
         fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) {
@@ -712,7 +712,10 @@ impl Merge for TomlConfig {
                 }
             }
         }
+
         self.change_id.inner.merge(change_id.inner, replace);
+        self.profile.merge(profile, replace);
+
         do_merge(&mut self.build, build, replace);
         do_merge(&mut self.install, install, replace);
         do_merge(&mut self.llvm, llvm, replace);
@@ -1505,6 +1508,10 @@ impl Config {
             build.cargo = build.cargo.take().or(std::env::var_os("CARGO").map(|p| p.into()));
         }
 
+        if GitInfo::new(false, &config.src).is_from_tarball() && toml.profile.is_none() {
+            toml.profile = Some("dist".into());
+        }
+
         if let Some(include) = &toml.profile {
             // Allows creating alias for profile names, allowing
             // profiles to be renamed while maintaining back compatibility
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index d408cd518a0..9234c6dc921 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -29,7 +29,7 @@ ENV PATH="/node/bin:${PATH}"
 
 # Install es-check
 # Pin its version to prevent unrelated CI failures due to future es-check versions.
-RUN npm install es-check@6.1.1 eslint@8.6.0 -g
+RUN npm install es-check@6.1.1 eslint@8.6.0 typescript@5.7.3 -g
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -68,4 +68,5 @@ ENV SCRIPT \
            es-check es2019 ../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
+           eslint -c ../src/tools/rustdoc-gui/.eslintrc.js ../src/tools/rustdoc-gui/tester.js && \
+           tsc --project ../src/librustdoc/html/static/js/tsconfig.json
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 4c4863e2b4b..2bbe3756580 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -5,7 +5,7 @@ runners:
     env: { }
 
   - &job-linux-4c
-    os: ubuntu-22.04
+    os: ubuntu-24.04
     # Free some disk space to avoid running out of space during the build.
     free_disk: true
     <<: *base-job
@@ -43,14 +43,14 @@ runners:
     os: windows-2022-8core-32gb
     <<: *base-job
 
-  - &job-windows-16c
-    os: windows-2022-16core-64gb
+  - &job-windows-25-8c
+    os: windows-2025-8core-32gb
     <<: *base-job
 
   - &job-aarch64-linux
     # Free some disk space to avoid running out of space during the build.
     free_disk: true
-    os: ubuntu-22.04-arm
+    os: ubuntu-24.04-arm
 
   - &job-aarch64-linux-8c
     os: ubuntu-22.04-arm64-8core-32gb
@@ -525,18 +525,16 @@ auto:
     env:
       RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
       SCRIPT: make ci-mingw
-      # We are intentionally allowing an old toolchain on this builder (and that's
-      # incompatible with LLVM downloads today).
+      # There is no dist-i686-mingw-alt, so there is no prebuilt LLVM with assertions
       NO_DOWNLOAD_CI_LLVM: 1
-    <<: *job-windows-8c
+    <<: *job-windows-25-8c
 
   # x86_64-mingw is split into two jobs to run tests in parallel.
   - name: x86_64-mingw-1
     env:
       SCRIPT: make ci-mingw-x
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
-      # We are intentionally allowing an old toolchain on this builder (and that's
-      # incompatible with LLVM downloads today).
+      # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions
       NO_DOWNLOAD_CI_LLVM: 1
     <<: *job-windows
 
@@ -544,8 +542,7 @@ auto:
     env:
       SCRIPT: make ci-mingw-bootstrap
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
-      # We are intentionally allowing an old toolchain on this builder (and that's
-      # incompatible with LLVM downloads today).
+      # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions
       NO_DOWNLOAD_CI_LLVM: 1
     <<: *job-windows
 
@@ -593,9 +590,6 @@ auto:
       RUST_CONFIGURE_ARGS: >-
         --build=i686-pc-windows-gnu
         --enable-full-tools
-      # We are intentionally allowing an old toolchain on this builder (and that's
-      # incompatible with LLVM downloads today).
-      NO_DOWNLOAD_CI_LLVM: 1
       SCRIPT: python x.py dist bootstrap --include-default-paths
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
@@ -607,9 +601,6 @@ auto:
       RUST_CONFIGURE_ARGS: >-
         --build=x86_64-pc-windows-gnu
         --enable-full-tools
-      # We are intentionally allowing an old toolchain on this builder (and that's
-      # incompatible with LLVM downloads today).
-      NO_DOWNLOAD_CI_LLVM: 1
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-windows
diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh
index 4a7dad0090b..8850e168145 100755
--- a/src/ci/scripts/free-disk-space.sh
+++ b/src/ci/scripts/free-disk-space.sh
@@ -1,8 +1,19 @@
 #!/bin/bash
+set -euo pipefail
 
 # Free disk space on Linux GitHub action runners
 # Script inspired by https://github.com/jlumbroso/free-disk-space
 
+isX86() {
+    local arch
+    arch=$(uname -m)
+    if [ "$arch" = "x86_64" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
 # print a line of the specified character
 printSeparationLine() {
     for ((i = 0; i < 80; i++)); do
@@ -14,11 +25,15 @@ printSeparationLine() {
 # compute available space
 # REF: https://unix.stackexchange.com/a/42049/60849
 # REF: https://stackoverflow.com/a/450821/408734
-getAvailableSpace() { echo $(df -a | awk 'NR > 1 {avail+=$4} END {print avail}'); }
+getAvailableSpace() {
+    df -a | awk 'NR > 1 {avail+=$4} END {print avail}'
+}
 
 # make Kb human readable (assume the input is Kb)
 # REF: https://unix.stackexchange.com/a/44087/60849
-formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); }
+formatByteCount() {
+    numfmt --to=iec-i --suffix=B --padding=7 "$1"'000'
+}
 
 # macro to output saved space
 printSavedSpace() {
@@ -58,11 +73,27 @@ removeDir() {
     dir=${1}
 
     local before
-    before=$(getAvailableSpace)
+    if [ ! -d "$dir" ]; then
+        echo "::warning::Directory $dir does not exist, skipping."
+    else
+        before=$(getAvailableSpace)
+        sudo rm -rf "$dir"
+        printSavedSpace "$before" "Removed $dir"
+    fi
+}
+
+removeUnusedDirectories() {
+    local dirs_to_remove=(
+        "/usr/local/lib/android"
+        "/usr/share/dotnet"
 
-    sudo rm -rf "$dir" || true
+        # Haskell runtime
+        "/usr/local/.ghcup"
+    )
 
-    printSavedSpace "$before" "$dir"
+    for dir in "${dirs_to_remove[@]}"; do
+        removeDir "$dir"
+    done
 }
 
 execAndMeasureSpaceChange() {
@@ -79,21 +110,29 @@ execAndMeasureSpaceChange() {
 # Remove large packages
 # REF: https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh
 cleanPackages() {
-    sudo apt-get -qq remove -y --fix-missing \
-        '^aspnetcore-.*'       \
-        '^dotnet-.*'           \
-        '^llvm-.*'             \
-        'php.*'                \
-        '^mongodb-.*'          \
-        '^mysql-.*'            \
-        'azure-cli'            \
-        'google-chrome-stable' \
-        'firefox'              \
-        'powershell'           \
-        'mono-devel'           \
-        'libgl1-mesa-dri'      \
-        'google-cloud-sdk'     \
-        'google-cloud-cli'
+    local packages=(
+        '^aspnetcore-.*'
+        '^dotnet-.*'
+        '^llvm-.*'
+        '^mongodb-.*'
+        '^mysql-.*'
+        'azure-cli'
+        'firefox'
+        'libgl1-mesa-dri'
+        'mono-devel'
+        'php.*'
+    )
+
+    if isX86; then
+        packages+=(
+            'google-chrome-stable'
+            'google-cloud-cli'
+            'google-cloud-sdk'
+            'powershell'
+        )
+    fi
+
+    sudo apt-get -qq remove -y --fix-missing "${packages[@]}"
 
     sudo apt-get autoremove -y || echo "::warning::The command [sudo apt-get autoremove -y] failed"
     sudo apt-get clean || echo "::warning::The command [sudo apt-get clean] failed failed"
@@ -101,9 +140,9 @@ cleanPackages() {
 
 # Remove Docker images
 cleanDocker() {
-    echo "Removing the following docker images:"
+    echo "=> Removing the following docker images:"
     sudo docker image ls
-    echo "Removing docker images..."
+    echo "=> Removing docker images..."
     sudo docker image prune --all --force || true
 }
 
@@ -121,17 +160,12 @@ AVAILABLE_INITIAL=$(getAvailableSpace)
 printDF "BEFORE CLEAN-UP:"
 echo ""
 
-removeDir /usr/local/lib/android
-removeDir /usr/share/dotnet
-
-# Haskell runtime
-removeDir /opt/ghc
-removeDir /usr/local/.ghcup
-
-execAndMeasureSpaceChange cleanPackages "Large misc. packages"
+execAndMeasureSpaceChange cleanPackages "Unused packages"
 execAndMeasureSpaceChange cleanDocker "Docker images"
 execAndMeasureSpaceChange cleanSwap "Swap storage"
 
+removeUnusedDirectories
+
 # Output saved space statistic
 echo ""
 printDF "AFTER CLEAN-UP:"
diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
index 006bcce44b3..3f810e2fbcc 100644
--- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml
+++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
@@ -41,7 +41,9 @@ jobs:
         uses: actions/cache/restore@v4
         with:
           path: book/linkcheck/cache.json
-          key: linkcheck--${{ env.MDBOOK_LINKCHECK2_VERSION }}
+          key: linkcheck--${{ env.MDBOOK_LINKCHECK2_VERSION }}--${{ github.run_id }}
+          restore-keys: |
+            linkcheck--${{ env.MDBOOK_LINKCHECK2_VERSION }}--
 
       - name: Install latest nightly Rust toolchain
         if: steps.mdbook-cache.outputs.cache-hit != 'true'
@@ -66,7 +68,7 @@ jobs:
         uses: actions/cache/save@v4
         with:
           path: book/linkcheck/cache.json
-          key: linkcheck--${{ env.MDBOOK_LINKCHECK2_VERSION }}
+          key: linkcheck--${{ env.MDBOOK_LINKCHECK2_VERSION }}--${{ github.run_id }}
 
       - name: Deploy to gh-pages
         if: github.event_name == 'push'
diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml
index 87a3ee2e78f..615927d55e5 100644
--- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml
+++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml
@@ -50,10 +50,10 @@ jobs:
           RESULT=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | length' --json title`
           if [[ "$RESULT" -eq 0 ]]; then
             echo "Creating new pull request"
-            PR_URL=gh pr create -B master --title 'Rustc pull update' --body 'Latest update from rustc.'
+            PR_URL=`gh pr create -B master --title 'Rustc pull update' --body 'Latest update from rustc.'`
             echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
           else
-            PR_URL=gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title
+            PR_URL=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title`
             echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
           fi
         env:
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
index 8983915d78a..b0f9af1b8d1 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
@@ -58,7 +58,7 @@ impl rustc_driver::Callbacks for MyCallbacks {
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &Compiler,
-        krate: &rustc_ast::Crate,
+        krate: &mut rustc_ast::Crate,
     ) -> Compilation {
         for item in &krate.items {
             println!("{}", item_to_string(&item));
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
index c894b60444a..8766a817344 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
@@ -58,7 +58,7 @@ impl rustc_driver::Callbacks for MyCallbacks {
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &Compiler,
-        krate: &rustc_ast::Crate,
+        krate: &mut rustc_ast::Crate,
     ) -> Compilation {
         for item in &krate.items {
             println!("{}", item_to_string(&item));
diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs
index be37dd867b2..2355cb85ab3 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs
@@ -10,6 +10,8 @@ extern crate rustc_interface;
 extern crate rustc_session;
 extern crate rustc_span;
 
+use std::sync::{Arc, Mutex};
+
 use rustc_errors::emitter::Emitter;
 use rustc_errors::registry::{self, Registry};
 use rustc_errors::translation::Translate;
@@ -17,8 +19,6 @@ use rustc_errors::{DiagCtxt, DiagInner, FluentBundle};
 use rustc_session::config;
 use rustc_span::source_map::SourceMap;
 
-use std::sync::{Arc, Mutex};
-
 struct DebugEmitter {
     source_map: Arc<SourceMap>,
     diagnostics: Arc<Mutex<Vec<DiagInner>>>,
@@ -67,10 +67,10 @@ fn main() {
         locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES.to_owned(),
         lint_caps: rustc_hash::FxHashMap::default(),
         psess_created: Some(Box::new(|parse_sess| {
-            parse_sess.set_dcx(DiagCtxt::new(Box::new(DebugEmitter {
+            parse_sess.dcx().set_emitter(Box::new(DebugEmitter {
                 source_map: parse_sess.clone_source_map(),
                 diagnostics,
-            })));
+            }));
         })),
         register_lints: None,
         override_queries: None,
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 9693bfd63e8..183d26b2938 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-ecda83b30f0f68cf5692855dddc0bc38ee8863fc
+66d6064f9eb888018775e08f84747ee6f39ba28e
diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md
index 793bfa9e66e..781a5c51bf7 100644
--- a/src/doc/rustc-dev-guide/src/about-this-guide.md
+++ b/src/doc/rustc-dev-guide/src/about-this-guide.md
@@ -72,7 +72,6 @@ You might also find the following sites useful:
 - The [Rust reference][rr], even though it doesn't specifically talk about
   Rust's internals, is a great resource nonetheless
 - Although out of date, [Tom Lee's great blog article][tlgba] is very helpful
-- [rustaceans.org][ro] is helpful, but mostly dedicated to IRC
 - The [Rust Compiler Testing Docs][rctd]
 - For [@bors], [this cheat sheet][cheatsheet] is helpful
 - Google is always helpful when programming.
diff --git a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
index b0823b9a5ee..556b3fdf8f8 100644
--- a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
+++ b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
@@ -42,7 +42,7 @@ format is specific to `rustc`, and may change over time. This file contains:
 ### dylib
 
 A `dylib` is a platform-specific shared library. It includes the `rustc`
-[metadata] in a special link section called `.rustc` in a compressed format.
+[metadata] in a special link section called `.rustc`.
 
 ### rmeta
 
diff --git a/src/doc/rustc-dev-guide/src/building/new-target.md b/src/doc/rustc-dev-guide/src/building/new-target.md
index 1d9fa1b52d5..cd215277e69 100644
--- a/src/doc/rustc-dev-guide/src/building/new-target.md
+++ b/src/doc/rustc-dev-guide/src/building/new-target.md
@@ -4,8 +4,13 @@ These are a set of steps to add support for a new target. There are
 numerous end states and paths to get there, so not all sections may be
 relevant to your desired goal.
 
+See also the associated documentation in the
+[target tier policy][target_tier_policy_add].
+
 <!-- toc -->
 
+[target_tier_policy_add]: https://doc.rust-lang.org/rustc/target-tier-policy.html#adding-a-new-target
+
 ## Specifying a new LLVM
 
 For very new targets, you may need to use a different fork of LLVM
diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md
index a2a6c8085df..e2097b26e5c 100644
--- a/src/doc/rustc-dev-guide/src/compiler-debugging.md
+++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md
@@ -275,7 +275,7 @@ Here are some notable ones:
 | `rustc_dump_def_parents` | Dumps the chain of `DefId` parents of certain definitions. |
 | `rustc_dump_item_bounds` | Dumps the [`item_bounds`] of an item. |
 | `rustc_dump_predicates` | Dumps the [`predicates_of`] an item. |
-| `rustc_dump_vtable` |  |
+| `rustc_dump_vtable` | Dumps the vtable layout of an impl, or a type alias of a dyn type. |
 | `rustc_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. |
 | `rustc_layout` | [See this section](#debugging-type-layouts). |
 | `rustc_object_lifetime_default` | Dumps the [object lifetime defaults] of an item. |
diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md
index 4010e90821f..0e624a4566d 100644
--- a/src/doc/rustc-dev-guide/src/conventions.md
+++ b/src/doc/rustc-dev-guide/src/conventions.md
@@ -43,7 +43,7 @@ environment.
 
 ## Formatting and linting Python code
 
-The Rust repository contains quite a lof of Python code. We try to keep
+The Rust repository contains quite a lot of Python code. We try to keep
 it both linted and formatted by the [ruff][ruff] tool.
 
 When modifying Python code, use this command to format it:
diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md
index 709e9d4f889..8f389640d27 100644
--- a/src/doc/rustc-dev-guide/src/diagnostics.md
+++ b/src/doc/rustc-dev-guide/src/diagnostics.md
@@ -602,7 +602,7 @@ as the linter walks the AST. You can then choose to emit lints in a
 very similar way to compile errors.
 
 You also declare the metadata of a particular lint via the `declare_lint!`
-macro. This includes the name, the default level, a short description, and some
+macro. [This macro](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/macro.declare_lint.html) includes the name, the default level, a short description, and some
 more details.
 
 Note that the lint and the lint pass must be registered with the compiler.
diff --git a/src/doc/rustc-dev-guide/src/early_late_parameters.md b/src/doc/rustc-dev-guide/src/early_late_parameters.md
index 6d13655294d..3b2a5e8a155 100644
--- a/src/doc/rustc-dev-guide/src/early_late_parameters.md
+++ b/src/doc/rustc-dev-guide/src/early_late_parameters.md
@@ -126,9 +126,9 @@ In this example we call `foo`'s function item type twice, each time with a borro
 If the lifetime parameter on `foo` was late bound this would be able to compile as each caller could provide a different lifetime argument for its borrow. See the following example which demonstrates this using the `bar` function defined above:
 
 ```rust
-#fn foo<'a: 'a>(b: &'a String) -> &'a String { b }
-#fn bar<'a>(b: &'a String) -> &'a String { b }
-
+# fn foo<'a: 'a>(b: &'a String) -> &'a String { b }
+# fn bar<'a>(b: &'a String) -> &'a String { b }
+#
 // Early bound parameters are instantiated here, however as `'a` is
 // late bound it is not provided here.
 let b = bar;
@@ -220,24 +220,24 @@ Then, for the first case, we can call each function with a single lifetime argum
 ```rust
 #![deny(late_bound_lifetime_arguments)]
 
-#fn free_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+# fn free_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
 #
-#struct Foo;
+# struct Foo;
 #
-#trait Trait: Sized {
-#    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ());
-#    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ());
-#}
+# trait Trait: Sized {
+#     fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ());
+#     fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ());
+# }
 #
-#impl Trait for Foo {
-#    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
-#    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
-#}
+# impl Trait for Foo {
+#     fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+#     fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+# }
 #
-#impl Foo {
-#    fn inherent_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
-#    fn inherent_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
-#}
+# impl Foo {
+#     fn inherent_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+#     fn inherent_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+# }
 #
 // Specifying as many arguments as there are early
 // bound parameters is always a future compat warning
@@ -251,24 +251,24 @@ free_function::<'static>(&(), &());
 
 For the second case we call each function with more lifetime arguments than there are lifetime parameters (be it early or late bound) and note that method calls result in a FCW as opposed to the free/associated functions which result in a hard error:
 ```rust
-#fn free_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+# fn free_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
 #
-#struct Foo;
+# struct Foo;
 #
-#trait Trait: Sized {
-#    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ());
-#    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ());
-#}
+# trait Trait: Sized {
+#     fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ());
+#     fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ());
+# }
 #
-#impl Trait for Foo {
-#    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
-#    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
-#}
+# impl Trait for Foo {
+#     fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+#     fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+# }
 #
-#impl Foo {
-#    fn inherent_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
-#    fn inherent_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
-#}
+# impl Foo {
+#     fn inherent_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+#     fn inherent_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+# }
 #
 // Specifying more arguments than there are early
 // bound parameters is a future compat warning when
@@ -421,4 +421,4 @@ impl<'a> Fn<()> for FooFnItem<'a> {
     type Output = &'a String;
     /* fn call(...) -> ... { ... } */
 }
-```
\ No newline at end of file
+```
diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md
index 03d2811e8b1..4cb1d0b31eb 100644
--- a/src/doc/rustc-dev-guide/src/getting-started.md
+++ b/src/doc/rustc-dev-guide/src/getting-started.md
@@ -137,6 +137,10 @@ pull request, continuing the work on the feature.
 
 [abandoned-prs]: https://github.com/rust-lang/rust/pulls?q=is%3Apr+label%3AS-inactive+is%3Aclosed
 
+### Writing tests
+
+Issues that have been resolved but do not have a regression test are marked with the `E-needs-test` label. Writing unit tests is a low-risk, lower-priority task that offers new contributors a great opportunity to familiarize themselves with the testing infrastructure and contribution workflow.
+
 ### Contributing to std (standard library)
 
 See [std-dev-guide](https://std-dev-guide.rust-lang.org/).
diff --git a/src/doc/rustc-dev-guide/src/rustdoc.md b/src/doc/rustc-dev-guide/src/rustdoc.md
index 3867d248988..2a0e212f98e 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc.md
@@ -58,10 +58,13 @@ does is call the `main()` that's in this crate's `lib.rs`, though.)
   * If you want to copy those docs to a webserver, copy all of
     `build/host/doc`, since that's where the CSS, JS, fonts, and landing
     page are.
+  * For frontend debugging, disable the `rust.docs-minification` option in [`config.toml`].
 * Use `./x test tests/rustdoc*` to run the tests using a stage1
   rustdoc.
   * See [Rustdoc internals] for more information about tests.
 
+[`config.toml`]: ./building/how-to-build-and-run.md
+
 ## Code structure
 
 * All paths in this section are relative to `src/librustdoc` in the rust-lang/rust repository.
@@ -77,6 +80,7 @@ does is call the `main()` that's in this crate's `lib.rs`, though.)
 * The tests on the structure of rustdoc HTML output are located in `tests/rustdoc`, where
   they're handled by the test runner of bootstrap and the supplementary script
   `src/etc/htmldocck.py`.
+* Frontend CSS and JavaScript are stored in `html/static/`.
 
 ## Tests
 
@@ -91,6 +95,11 @@ does is call the `main()` that's in this crate's `lib.rs`, though.)
   browser-UI-test](https://github.com/GuillaumeGomez/browser-UI-test/) that uses
   puppeteer to run tests in a headless browser and check rendering and
   interactivity.
+* Additionally, JavaScript type annotations are written using [TypeScript-flavored JSDoc]
+  comments and an external d.ts file. The code itself is plain, valid JavaScript; we only
+  use tsc as a linter.
+
+[TypeScript-flavored JSDoc]: https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
 
 ## Constraints
 
diff --git a/src/doc/rustc-dev-guide/src/solve/significant-changes.md b/src/doc/rustc-dev-guide/src/solve/significant-changes.md
index c5bb8a01b12..c82b5d46896 100644
--- a/src/doc/rustc-dev-guide/src/solve/significant-changes.md
+++ b/src/doc/rustc-dev-guide/src/solve/significant-changes.md
@@ -42,7 +42,7 @@ old implementation structurally relates the aliases instead. This enables the
 new solver to stall equality until it is able to normalize the related aliases.
 
 The behavior of the old solver is incomplete and relies on eager normalization
-which replaces ambiguous aliases with inference variables. As this is not
+which replaces ambiguous aliases with inference variables. As this is
 not possible for aliases containing bound variables, the old implementation does
 not handle aliases inside of binders correctly, e.g. [#102048]. See the chapter on
 [normalization] for more details.
diff --git a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md
index 63b09a43f47..05693dcd5a1 100644
--- a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md
+++ b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md
@@ -40,7 +40,7 @@ requirements of impls and functions as explicit predicates.
 ### using implicit implied bounds as assumptions
 
 These bounds are not added to the `ParamEnv` of the affected item itself. For lexical
-region resolution they are added using [`fn OutlivesEnvironment::with_bounds`].
+region resolution they are added using [`fn OutlivesEnvironment::new`].
 Similarly, during MIR borrowck we add them using
 [`fn UniversalRegionRelationsBuilder::add_implied_bounds`].
 
@@ -55,7 +55,7 @@ The assumed outlives constraints for implicit bounds are computed using the
 MIR borrowck adds the outlives constraints for both the normalized and unnormalized types,
 lexical region resolution [only uses the unnormalized types][notnorm].
 
-[`fn OutlivesEnvironment::with_bounds`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_infer/src/infer/outlives/env.rs#L90-L97
+[`fn OutlivesEnvironment::new`]: TODO
 [`fn UniversalRegionRelationsBuilder::add_implied_bounds`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L316
 [mir]: https://github.com/rust-lang/rust/blob/91cae1dcdcf1a31bd8a92e4a63793d65cfe289bb/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L258-L332
 [`fn assumed_wf_types`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_ty_utils/src/implied_bounds.rs#L21
diff --git a/src/doc/rustc/src/profile-guided-optimization.md b/src/doc/rustc/src/profile-guided-optimization.md
index 38b655b7542..4050494793a 100644
--- a/src/doc/rustc/src/profile-guided-optimization.md
+++ b/src/doc/rustc/src/profile-guided-optimization.md
@@ -3,7 +3,7 @@
 `rustc` supports doing profile-guided optimization (PGO).
 This chapter describes what PGO is, what it is good for, and how it can be used.
 
-## What Is Profiled-Guided Optimization?
+## What Is Profile-Guided Optimization?
 
 The basic concept of PGO is to collect data about the typical execution of
 a program (e.g. which branches it is likely to take) and then use this data
diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md
index bdcf2c0b07e..a0acfdf0e4a 100644
--- a/src/doc/rustc/src/target-tier-policy.md
+++ b/src/doc/rustc/src/target-tier-policy.md
@@ -122,12 +122,23 @@ To propose addition of a new target, open a pull request on [`rust-lang/rust`]:
   r? compiler
   ```
 
+See also the documentation in the `rustc-dev-guide` on [adding a new target to
+`rustc`][rustc_dev_guide_add_target].
+
+Note that adding a new target that wants to support `std` would transitively
+require `cc` and `libc` support. However, these would like to know about the
+target from `rustc` as well. To break this cycle, you are strongly encouraged
+to add a _minimal_ `#![no_core]` target spec first to teach `rustc` about the
+target's existence, and add `std` support as a follow-up once you've added
+support for the target in `cc` and `libc`.
+
 [tier3example]: https://github.com/rust-lang/rust/pull/94872
 [platform_template]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/platform-support/TEMPLATE.md
 [summary]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/SUMMARY.md
 [platformsupport]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/platform-support.md
 [rust_compiler_team]: https://www.rust-lang.org/governance/teams/compiler
 [`rust-lang/rust`]: https://github.com/rust-lang/rust
+[rustc_dev_guide_add_target]: https://rustc-dev-guide.rust-lang.org/building/new-target.html
 
 ## Tier 3 target policy
 
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index d1d42e47322..7eb1b8df233 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -524,6 +524,8 @@ use `-o -`.
 
 ## `-w`/`--output-format`: output format
 
+### json
+
 `--output-format json` emits documentation in the experimental
 [JSON format](https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc_json_types/). `--output-format html` has no effect,
 and is also accepted on stable toolchains.
@@ -542,6 +544,68 @@ It can also be used with `--show-coverage`. Take a look at its
 [documentation](#--show-coverage-calculate-the-percentage-of-items-with-documentation) for more
 information.
 
+### doctest
+
+`--output-format doctest` emits JSON on stdout which gives you information about doctests in the
+provided crate.
+
+Tracking issue: [#134529](https://github.com/rust-lang/rust/issues/134529)
+
+You can use this option like this:
+
+```bash
+rustdoc -Zunstable-options --output-format=doctest src/lib.rs
+```
+
+For this rust code:
+
+```rust
+/// ```
+/// let x = 12;
+/// ```
+pub trait Trait {}
+```
+
+The generated output (formatted) will look like this:
+
+```json
+{
+  "format_version": 1,
+  "doctests": [
+    {
+      "file": "foo.rs",
+      "line": 1,
+      "doctest_attributes": {
+        "original": "",
+        "should_panic": false,
+        "no_run": false,
+        "ignore": "None",
+        "rust": true,
+        "test_harness": false,
+        "compile_fail": false,
+        "standalone_crate": false,
+        "error_codes": [],
+        "edition": null,
+        "added_css_classes": [],
+        "unknown": []
+      },
+      "original_code": "let x = 12;",
+      "doctest_code": "#![allow(unused)]\nfn main() {\nlet x = 12;\n}",
+      "name": "foo.rs - Trait (line 1)"
+    }
+  ]
+}
+```
+
+ * `format_version` gives you the current version of the generated JSON. If we change the output in any way, the number will increase.
+ * `doctests` contains the list of doctests present in the crate.
+   * `file` is the file path where the doctest is located.
+   * `line` is the line where the doctest starts (so where the \`\`\` is located in the current code).
+   * `doctest_attributes` contains computed information about the attributes used on the doctests. For more information about doctest attributes, take a look [here](write-documentation/documentation-tests.html#attributes).
+   * `original_code` is the code as written in the source code before rustdoc modifies it.
+   * `doctest_code` is the code modified by rustdoc that will be run. If there is a fatal syntax error, this field will not be present.
+   * `name` is the name generated by rustdoc which represents this doctest.
+
 ## `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
 
  * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md
index b9a89c20cee..19e62c4867c 100644
--- a/src/doc/style-guide/src/editions.md
+++ b/src/doc/style-guide/src/editions.md
@@ -36,10 +36,6 @@ For a full history of changes in the Rust 2024 style edition, see the git
 history of the style guide. Notable changes in the Rust 2024 style edition
 include:
 
-- [#114764](https://github.com/rust-lang/rust/pull/114764) As the last member
-  of a delimited expression, delimited expressions are generally combinable,
-  regardless of the number of members. Previously only applied with exactly
-  one member (except for closures with explicit blocks).
 - Miscellaneous `rustfmt` bugfixes.
 - Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
 - Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
index 171a24cd89d..12037b5992e 100644
--- a/src/doc/style-guide/src/expressions.md
+++ b/src/doc/style-guide/src/expressions.md
@@ -818,11 +818,11 @@ E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not.
 
 ## Combinable expressions
 
-When the last argument in a function call is formatted across
-multiple-lines, format the outer call as if it were a single-line call,
+Where a function call has a single argument, and that argument is formatted
+across multiple-lines, format the outer call as if it were a single-line call,
 if the result fits. Apply the same combining behaviour to any similar
 expressions which have multi-line, block-indented lists of sub-expressions
-delimited by parentheses, brackets, or braces. E.g.,
+delimited by parentheses (e.g., macros or tuple struct literals). E.g.,
 
 ```rust
 foo(bar(
@@ -848,61 +848,20 @@ let arr = [combinable(
     an_expr,
     another_expr,
 )];
-
-let x = Thing(an_expr, another_expr, match cond {
-    A => 1,
-    B => 2,
-});
-
-let x = format!("Stuff: {}", [
-    an_expr,
-    another_expr,
-]);
-
-let x = func(an_expr, another_expr, SomeStruct {
-    field: this_is_long,
-    another_field: 123,
-});
 ```
 
 Apply this behavior recursively.
 
-If the last argument is a multi-line closure with an explicit block,
-only apply the combining behavior if there are no other closure arguments.
+For a function with multiple arguments, if the last argument is a multi-line
+closure with an explicit block, there are no other closure arguments, and all
+the arguments and the first line of the closure fit on the first line, use the
+same combining behavior:
 
 ```rust
-// Combinable
 foo(first_arg, x, |param| {
     action();
     foo(param)
 })
-// Not combinable, because the closure is not the last argument
-foo(
-    first_arg,
-    |param| {
-        action();
-        foo(param)
-    },
-    whatever,
-)
-// Not combinable, because the first line of the closure does not fit
-foo(
-    first_arg,
-    x,
-    move |very_long_param_causing_line_to_overflow| -> Bar {
-        action();
-        foo(param)
-    },
-)
-// Not combinable, because there is more than one closure argument
-foo(
-    first_arg,
-    |x| x.bar(),
-    |param| {
-        action();
-        foo(param)
-    },
-)
 ```
 
 ## Ranges
diff --git a/src/doc/unstable-book/src/compiler-flags/autodiff.md b/src/doc/unstable-book/src/compiler-flags/autodiff.md
new file mode 100644
index 00000000000..4e55be0ad95
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/autodiff.md
@@ -0,0 +1,23 @@
+# `autodiff`
+
+The tracking issue for this feature is: [#124509](https://github.com/rust-lang/rust/issues/124509).
+
+------------------------
+
+This feature allows you to differentiate functions using automatic differentiation.
+Set the `-Zautodiff=<options>` compiler flag to adjust the behaviour of the autodiff feature.
+Multiple options can be separated with a comma. Valid options are:
+
+`PrintTA` - print Type Analysis Information
+`PrintAA` - print Activity Analysis Information
+`PrintPerf` - print Performance Warnings from Enzyme
+`Print` - prints all intermediate transformations
+`PrintModBefore` - print the whole module, before running opts
+`PrintModAfterOpts` - print the whole module just before we pass it to Enzyme
+`PrintModAfterEnzyme` - print the module after Enzyme differentiated everything
+`LooseTypes` - Enzyme's loose type debug helper (can cause incorrect gradients)
+`Inline` - runs Enzyme specific Inlining
+`NoModOptAfter` - do not optimize the module after Enzyme is done
+`EnableFncOpt` - tell Enzyme to run LLVM Opts on each function it generated
+`NoVecUnroll` - do not unroll vectorized loops
+`RuntimeActivity` - allow specifying activity at runtime
diff --git a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
index c5e86f17df7..e88799d2cf0 100644
--- a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
+++ b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
@@ -1,5 +1,9 @@
 ## `dwarf-version`
 
+The tracking issue for this feature is: <https://github.com/rust-lang/rust/issues/103057>
+
+----------------------------
+
 This option controls the version of DWARF that the compiler emits, on platforms
 that use DWARF to encode debug information. It takes one of the following
 values:
diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md
new file mode 100644
index 00000000000..bc587686111
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md
@@ -0,0 +1,19 @@
+# `ref_pat_eat_one_layer_2024_structural`
+
+The tracking issue for this feature is: [#123076]
+
+[#123076]: https://github.com/rust-lang/rust/issues/123076
+
+---
+
+This feature is incomplete and not yet intended for general use.
+
+This implements experimental, Edition-dependent match ergonomics under consideration for inclusion
+in Rust.
+For more information, see the corresponding typing rules for [Editions 2024 and later].
+On earlier Editions, the current behavior is unspecified.
+
+For alternative experimental match ergonomics, see the feature
+[`ref_pat_eat_one_layer_2024`](./ref-pat-eat-one-layer-2024.md).
+
+[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAgEBAQEBAgIAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false
diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md
new file mode 100644
index 00000000000..43de1849a5e
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md
@@ -0,0 +1,19 @@
+# `ref_pat_eat_one_layer_2024`
+
+The tracking issue for this feature is: [#123076]
+
+[#123076]: https://github.com/rust-lang/rust/issues/123076
+
+---
+
+This feature is incomplete and not yet intended for general use.
+
+This implements experimental, Edition-dependent match ergonomics under consideration for inclusion
+in Rust.
+For more information, see the corresponding typing rules for [Editions 2024 and later].
+On earlier Editions, the current behavior is unspecified.
+
+For alternative experimental match ergonomics, see the feature
+[`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md).
+
+[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false
diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs
index 69337fb1d25..b4b0a8d0615 100644
--- a/src/librustdoc/build.rs
+++ b/src/librustdoc/build.rs
@@ -17,10 +17,15 @@ fn main() {
         "static/images/rust-logo.svg",
         "static/images/favicon.svg",
         "static/images/favicon-32x32.png",
+        "static/fonts/FiraSans-Italic.woff2",
         "static/fonts/FiraSans-Regular.woff2",
         "static/fonts/FiraSans-Medium.woff2",
+        "static/fonts/FiraSans-MediumItalic.woff2",
+        "static/fonts/FiraMono-Regular.woff2",
+        "static/fonts/FiraMono-Medium.woff2",
         "static/fonts/FiraSans-LICENSE.txt",
         "static/fonts/SourceSerif4-Regular.ttf.woff2",
+        "static/fonts/SourceSerif4-Semibold.ttf.woff2",
         "static/fonts/SourceSerif4-Bold.ttf.woff2",
         "static/fonts/SourceSerif4-It.ttf.woff2",
         "static/fonts/SourceSerif4-LICENSE.md",
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 6e817af0d6e..a44d74e6df6 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -5,9 +5,7 @@ use std::{fmt, iter};
 
 use arrayvec::ArrayVec;
 use rustc_abi::{ExternAbi, VariantIdx};
-use rustc_attr_parsing::{
-    AllowedThroughUnstableModules, ConstStability, Deprecation, Stability, StableSince,
-};
+use rustc_attr_parsing::{ConstStability, Deprecation, Stability, StableSince};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
@@ -411,15 +409,9 @@ impl Item {
                 ..
             } = stab.level
             {
-                let note = match note {
-                    AllowedThroughUnstableModules::WithDeprecation(note) => Some(note),
-                    // FIXME: Would be better to say *something* here about the *path* being
-                    // deprecated rather than the item.
-                    AllowedThroughUnstableModules::WithoutDeprecation => None,
-                };
                 Some(Deprecation {
                     since: rustc_attr_parsing::DeprecatedSince::Unspecified,
-                    note,
+                    note: Some(note),
                     suggestion: None,
                 })
             } else {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 80dc6b7250c..0b4fd9c2258 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -303,7 +303,8 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
             return kw::Underscore;
         }
         PatKind::Binding(_, _, ident, _) => return ident.name,
-        PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
+        PatKind::TupleStruct(ref p, ..)
+        | PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref p), .. }) => qpath_to_string(p),
         PatKind::Or(pats) => {
             pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ")
         }
@@ -343,10 +344,8 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
             s
         }
         // array lengths are obviously usize
-        ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar))
-            if *ty.kind() == ty::Uint(ty::UintTy::Usize) =>
-        {
-            scalar.to_string()
+        ty::ConstKind::Value(cv) if *cv.ty.kind() == ty::Uint(ty::UintTy::Usize) => {
+            cv.valtree.unwrap_leaf().to_string()
         }
         _ => n.to_string(),
     }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 80bc6cebd2a..c6fb70eee08 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -9,8 +9,8 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::DiagCtxtHandle;
 use rustc_session::config::{
     self, CodegenOptions, CrateType, ErrorOutputType, Externs, Input, JsonUnusedExterns,
-    UnstableOptions, get_cmd_lint_options, nightly_options, parse_crate_types_from_list,
-    parse_externs, parse_target_triple,
+    OptionsTargetModifiers, UnstableOptions, get_cmd_lint_options, nightly_options,
+    parse_crate_types_from_list, parse_externs, parse_target_triple,
 };
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
@@ -33,6 +33,7 @@ pub(crate) enum OutputFormat {
     Json,
     #[default]
     Html,
+    Doctest,
 }
 
 impl OutputFormat {
@@ -48,6 +49,7 @@ impl TryFrom<&str> for OutputFormat {
         match value {
             "json" => Ok(OutputFormat::Json),
             "html" => Ok(OutputFormat::Html),
+            "doctest" => Ok(OutputFormat::Doctest),
             _ => Err(format!("unknown output format `{value}`")),
         }
     }
@@ -387,8 +389,9 @@ impl Options {
             config::parse_error_format(early_dcx, matches, color, json_color, json_rendered);
         let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
 
-        let codegen_options = CodegenOptions::build(early_dcx, matches);
-        let unstable_opts = UnstableOptions::build(early_dcx, matches);
+        let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new();
+        let codegen_options = CodegenOptions::build(early_dcx, matches, &mut target_modifiers);
+        let unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
 
         let remap_path_prefix = match parse_remap_path_prefix(matches) {
             Ok(prefix_mappings) => prefix_mappings,
@@ -445,14 +448,42 @@ impl Options {
             }
         }
 
+        let show_coverage = matches.opt_present("show-coverage");
+        let output_format_s = matches.opt_str("output-format");
+        let output_format = match output_format_s {
+            Some(ref s) => match OutputFormat::try_from(s.as_str()) {
+                Ok(out_fmt) => out_fmt,
+                Err(e) => dcx.fatal(e),
+            },
+            None => OutputFormat::default(),
+        };
+
         // check for `--output-format=json`
-        if !matches!(matches.opt_str("output-format").as_deref(), None | Some("html"))
-            && !matches.opt_present("show-coverage")
-            && !nightly_options::is_unstable_enabled(matches)
-        {
-            dcx.fatal(
-                "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)",
-            );
+        match (
+            output_format_s.as_ref().map(|_| output_format),
+            show_coverage,
+            nightly_options::is_unstable_enabled(matches),
+        ) {
+            (None | Some(OutputFormat::Json), true, _) => {}
+            (_, true, _) => {
+                dcx.fatal(format!(
+                    "`--output-format={}` is not supported for the `--show-coverage` option",
+                    output_format_s.unwrap_or_default(),
+                ));
+            }
+            // If `-Zunstable-options` is used, nothing to check after this point.
+            (_, false, true) => {}
+            (None | Some(OutputFormat::Html), false, _) => {}
+            (Some(OutputFormat::Json), false, false) => {
+                dcx.fatal(
+                    "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)",
+                );
+            }
+            (Some(OutputFormat::Doctest), false, false) => {
+                dcx.fatal(
+                    "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/134529)",
+                );
+            }
         }
 
         let to_check = matches.opt_strs("check-theme");
@@ -704,8 +735,6 @@ impl Options {
             })
             .collect();
 
-        let show_coverage = matches.opt_present("show-coverage");
-
         let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) {
             Ok(types) => types,
             Err(e) => {
@@ -713,20 +742,6 @@ impl Options {
             }
         };
 
-        let output_format = match matches.opt_str("output-format") {
-            Some(s) => match OutputFormat::try_from(s.as_str()) {
-                Ok(out_fmt) => {
-                    if !out_fmt.is_json() && show_coverage {
-                        dcx.fatal(
-                            "html output format isn't supported for the --show-coverage option",
-                        );
-                    }
-                    out_fmt
-                }
-                Err(e) => dcx.fatal(e),
-            },
-            None => OutputFormat::default(),
-        };
         let crate_name = matches.opt_str("crate-name");
         let bin_crate = crate_types.contains(&CrateType::Executable);
         let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 0437ebb5857..a072b1256f4 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -336,14 +336,14 @@ pub(crate) fn run_global_ctxt(
 
     // NOTE: These are copy/pasted from typeck/lib.rs and should be kept in sync with those changes.
     let _ = tcx.sess.time("wf_checking", || {
-        tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
+        tcx.hir().try_par_for_each_module(|module| tcx.ensure_ok().check_mod_type_wf(module))
     });
 
     tcx.dcx().abort_if_errors();
 
     tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx));
     tcx.sess.time("check_mod_attrs", || {
-        tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module))
+        tcx.hir().for_each_module(|module| tcx.ensure_ok().check_mod_attrs(module))
     });
     rustc_passes::stability::check_unused_or_stable_features(tcx);
 
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 8c3e28ecec3..8b522e614b8 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1,3 +1,4 @@
+mod extracted;
 mod make;
 mod markdown;
 mod runner;
@@ -30,7 +31,7 @@ use tempfile::{Builder as TempFileBuilder, TempDir};
 use tracing::debug;
 
 use self::rust::HirCollector;
-use crate::config::Options as RustdocOptions;
+use crate::config::{Options as RustdocOptions, OutputFormat};
 use crate::html::markdown::{ErrorCodes, Ignore, LangString, MdRelLine};
 use crate::lint::init_lints;
 
@@ -209,15 +210,8 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
     let args_path = temp_dir.path().join("rustdoc-cfgs");
     crate::wrap_return(dcx, generate_args_file(&args_path, &options));
 
-    let CreateRunnableDocTests {
-        standalone_tests,
-        mergeable_tests,
-        rustdoc_options,
-        opts,
-        unused_extern_reports,
-        compiling_test_count,
-        ..
-    } = interface::run_compiler(config, |compiler| {
+    let extract_doctests = options.output_format == OutputFormat::Doctest;
+    let result = interface::run_compiler(config, |compiler| {
         let krate = rustc_interface::passes::parse(&compiler.sess);
 
         let collector = rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
@@ -226,22 +220,53 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
             let opts = scrape_test_config(crate_name, crate_attrs, args_path);
             let enable_per_target_ignores = options.enable_per_target_ignores;
 
-            let mut collector = CreateRunnableDocTests::new(options, opts);
             let hir_collector = HirCollector::new(
                 ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()),
                 enable_per_target_ignores,
                 tcx,
             );
             let tests = hir_collector.collect_crate();
-            tests.into_iter().for_each(|t| collector.add_test(t));
+            if extract_doctests {
+                let mut collector = extracted::ExtractedDocTests::new();
+                tests.into_iter().for_each(|t| collector.add_test(t, &opts, &options));
+
+                let stdout = std::io::stdout();
+                let mut stdout = stdout.lock();
+                if let Err(error) = serde_json::ser::to_writer(&mut stdout, &collector) {
+                    eprintln!();
+                    Err(format!("Failed to generate JSON output for doctests: {error:?}"))
+                } else {
+                    Ok(None)
+                }
+            } else {
+                let mut collector = CreateRunnableDocTests::new(options, opts);
+                tests.into_iter().for_each(|t| collector.add_test(t));
 
-            collector
+                Ok(Some(collector))
+            }
         });
         compiler.sess.dcx().abort_if_errors();
 
         collector
     });
 
+    let CreateRunnableDocTests {
+        standalone_tests,
+        mergeable_tests,
+        rustdoc_options,
+        opts,
+        unused_extern_reports,
+        compiling_test_count,
+        ..
+    } = match result {
+        Ok(Some(collector)) => collector,
+        Ok(None) => return,
+        Err(error) => {
+            eprintln!("{error}");
+            std::process::exit(1);
+        }
+    };
+
     run_tests(opts, &rustdoc_options, &unused_extern_reports, standalone_tests, mergeable_tests);
 
     let compiling_test_count = compiling_test_count.load(Ordering::SeqCst);
diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs
new file mode 100644
index 00000000000..03c8814a4c9
--- /dev/null
+++ b/src/librustdoc/doctest/extracted.rs
@@ -0,0 +1,141 @@
+//! Rustdoc's doctest extraction.
+//!
+//! This module contains the logic to extract doctests and output a JSON containing this
+//! information.
+
+use serde::Serialize;
+
+use super::{DocTestBuilder, ScrapedDocTest};
+use crate::config::Options as RustdocOptions;
+use crate::html::markdown;
+
+/// The version of JSON output that this code generates.
+///
+/// This integer is incremented with every breaking change to the API,
+/// and is returned along with the JSON blob into the `format_version` root field.
+/// Consuming code should assert that this value matches the format version(s) that it supports.
+const FORMAT_VERSION: u32 = 1;
+
+#[derive(Serialize)]
+pub(crate) struct ExtractedDocTests {
+    format_version: u32,
+    doctests: Vec<ExtractedDocTest>,
+}
+
+impl ExtractedDocTests {
+    pub(crate) fn new() -> Self {
+        Self { format_version: FORMAT_VERSION, doctests: Vec::new() }
+    }
+
+    pub(crate) fn add_test(
+        &mut self,
+        scraped_test: ScrapedDocTest,
+        opts: &super::GlobalTestOptions,
+        options: &RustdocOptions,
+    ) {
+        let edition = scraped_test.edition(&options);
+
+        let ScrapedDocTest { filename, line, langstr, text, name } = scraped_test;
+
+        let doctest = DocTestBuilder::new(
+            &text,
+            Some(&opts.crate_name),
+            edition,
+            false,
+            None,
+            Some(&langstr),
+        );
+        let (full_test_code, size) = doctest.generate_unique_doctest(
+            &text,
+            langstr.test_harness,
+            &opts,
+            Some(&opts.crate_name),
+        );
+        self.doctests.push(ExtractedDocTest {
+            file: filename.prefer_remapped_unconditionaly().to_string(),
+            line,
+            doctest_attributes: langstr.into(),
+            doctest_code: if size != 0 { Some(full_test_code) } else { None },
+            original_code: text,
+            name,
+        });
+    }
+}
+
+#[derive(Serialize)]
+pub(crate) struct ExtractedDocTest {
+    file: String,
+    line: usize,
+    doctest_attributes: LangString,
+    original_code: String,
+    /// `None` if the code syntax is invalid.
+    doctest_code: Option<String>,
+    name: String,
+}
+
+#[derive(Serialize)]
+pub(crate) enum Ignore {
+    All,
+    None,
+    Some(Vec<String>),
+}
+
+impl From<markdown::Ignore> for Ignore {
+    fn from(original: markdown::Ignore) -> Self {
+        match original {
+            markdown::Ignore::All => Self::All,
+            markdown::Ignore::None => Self::None,
+            markdown::Ignore::Some(values) => Self::Some(values),
+        }
+    }
+}
+
+#[derive(Serialize)]
+struct LangString {
+    pub(crate) original: String,
+    pub(crate) should_panic: bool,
+    pub(crate) no_run: bool,
+    pub(crate) ignore: Ignore,
+    pub(crate) rust: bool,
+    pub(crate) test_harness: bool,
+    pub(crate) compile_fail: bool,
+    pub(crate) standalone_crate: bool,
+    pub(crate) error_codes: Vec<String>,
+    pub(crate) edition: Option<String>,
+    pub(crate) added_css_classes: Vec<String>,
+    pub(crate) unknown: Vec<String>,
+}
+
+impl From<markdown::LangString> for LangString {
+    fn from(original: markdown::LangString) -> Self {
+        let markdown::LangString {
+            original,
+            should_panic,
+            no_run,
+            ignore,
+            rust,
+            test_harness,
+            compile_fail,
+            standalone_crate,
+            error_codes,
+            edition,
+            added_classes,
+            unknown,
+        } = original;
+
+        Self {
+            original,
+            should_panic,
+            no_run,
+            ignore: ignore.into(),
+            rust,
+            test_harness,
+            compile_fail,
+            standalone_crate,
+            error_codes,
+            edition: edition.map(|edition| edition.to_string()),
+            added_css_classes: added_classes,
+            unknown,
+        }
+    }
+}
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 85f87f01afd..a15ac155123 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -4,7 +4,9 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatKind, QPath};
+use rustc_hir::{
+    ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatExpr, PatExprKind, PatKind, QPath,
+};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::hygiene::MacroKind;
@@ -191,17 +193,21 @@ impl SpanMapVisitor<'_> {
     }
 
     fn handle_pat(&mut self, p: &Pat<'_>) {
+        let mut check_qpath = |qpath, hir_id| match qpath {
+            QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
+                self.infer_id(path.hir_id, Some(hir_id), qpath.span());
+            }
+            QPath::Resolved(_, path) => self.handle_path(path),
+            _ => {}
+        };
         match p.kind {
             PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p),
-            PatKind::Struct(qpath, _, _)
-            | PatKind::TupleStruct(qpath, _, _)
-            | PatKind::Path(qpath) => match qpath {
-                QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
-                    self.infer_id(path.hir_id, Some(p.hir_id), qpath.span());
-                }
-                QPath::Resolved(_, path) => self.handle_path(path),
-                _ => {}
-            },
+            PatKind::Struct(qpath, _, _) | PatKind::TupleStruct(qpath, _, _) => {
+                check_qpath(qpath, p.hir_id)
+            }
+            PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, .. }) => {
+                check_qpath(*qpath, *hir_id)
+            }
             PatKind::Or(pats) => {
                 for pat in pats {
                     self.handle_pat(pat);
diff --git a/src/librustdoc/html/static/COPYRIGHT.txt b/src/librustdoc/html/static/COPYRIGHT.txt
index 1447df792f6..111340298c5 100644
--- a/src/librustdoc/html/static/COPYRIGHT.txt
+++ b/src/librustdoc/html/static/COPYRIGHT.txt
@@ -36,7 +36,7 @@ included, and carry their own copyright notices and license terms:
     See SourceCodePro-LICENSE.txt.
 
 * Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2,
-    SourceSerif4-It.ttf.woff2):
+    SourceSerif4-It.ttf.woff2, SourceSerif4-Semibold.ttf.woff2):
 
     Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name
     'Source'. All Rights Reserved. Source is a trademark of Adobe in the United
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index f487d66edac..d0612e997fd 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -38,6 +38,13 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
 	--code-block-border-radius: 6px;
 	--impl-items-indent: 0.3em;
 	--docblock-indent: 24px;
+	--font-family: "Source Serif 4", NanumBarunGothic, serif;
+	--font-family-code: "Source Code Pro", monospace;
+}
+
+:root.sans-serif {
+	--font-family: "Fira Sans", sans-serif;
+	--font-family-code: "Fira Mono", monospace;
 }
 
 /* See FiraSans-LICENSE.txt for the Fira Sans license. */
@@ -51,12 +58,44 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
 }
 @font-face {
 	font-family: 'Fira Sans';
+	font-style: italic;
+	font-weight: 400;
+	src: local('Fira Sans Italic'),
+		url("FiraSans-Italic-81dc35de.woff2") format("woff2");
+	font-display: swap;
+}
+@font-face {
+	font-family: 'Fira Sans';
 	font-style: normal;
 	font-weight: 500;
 	src: local('Fira Sans Medium'),
 		url("FiraSans-Medium-e1aa3f0a.woff2") format("woff2");
 	font-display: swap;
 }
+@font-face {
+	font-family: 'Fira Sans';
+	font-style: italic;
+	font-weight: 500;
+	src: local('Fira Sans Medium Italic'),
+		url("FiraSans-MediumItalic-ccf7e434.woff2") format("woff2");
+	font-display: swap;
+}
+@font-face {
+	font-family: 'Fira Mono';
+	font-style: normal;
+	font-weight: 400;
+	src: local('Fira Mono'),
+		url("FiraMono-Regular-87c26294.woff2") format("woff2");
+	font-display: swap;
+}
+@font-face {
+	font-family: 'Fira Mono';
+	font-style: normal;
+	font-weight: 500;
+	src: local('Fira Mono Medium'),
+		url("FiraMono-Medium-86f75c8c.woff2") format("woff2");
+	font-display: swap;
+}
 
 /* See SourceSerif4-LICENSE.md for the Source Serif 4 license. */
 @font-face {
@@ -78,6 +117,14 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
 @font-face {
 	font-family: 'Source Serif 4';
 	font-style: normal;
+	font-weight: 500;
+	src: local('Source Serif 4 Semibold'),
+		url("SourceSerif4-Semibold-457a13ac.ttf.woff2") format("woff2");
+	font-display: swap;
+}
+@font-face {
+	font-family: 'Source Serif 4';
+	font-style: normal;
 	font-weight: 700;
 	src: local('Source Serif 4 Bold'),
 		url("SourceSerif4-Bold-6d4fd4c0.ttf.woff2") format("woff2");
@@ -126,7 +173,7 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
 body {
 	/* Line spacing at least 1.5 per Web Content Accessibility Guidelines
 	   https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */
-	font: 1rem/1.5 "Source Serif 4", NanumBarunGothic, serif;
+	font: 1rem/1.5 var(--font-family);
 	margin: 0;
 	position: relative;
 	/* We use overflow-wrap: break-word for Safari, which doesn't recognize
@@ -380,7 +427,7 @@ details:not(.toggle) summary {
 }
 
 code, pre, .code-header, .type-signature {
-	font-family: "Source Code Pro", monospace;
+	font-family: var(--font-family-code);
 }
 .docblock code, .item-table dd code {
 	border-radius: 3px;
diff --git a/src/librustdoc/html/static/fonts/FiraMono-Medium.woff2 b/src/librustdoc/html/static/fonts/FiraMono-Medium.woff2
new file mode 100755
index 00000000000..610e9b2071e
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/FiraMono-Medium.woff2
Binary files differdiff --git a/src/librustdoc/html/static/fonts/FiraMono-Regular.woff2 b/src/librustdoc/html/static/fonts/FiraMono-Regular.woff2
new file mode 100755
index 00000000000..9fa44b7cc2d
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/FiraMono-Regular.woff2
Binary files differdiff --git a/src/librustdoc/html/static/fonts/FiraSans-Italic.woff2 b/src/librustdoc/html/static/fonts/FiraSans-Italic.woff2
new file mode 100755
index 00000000000..3f63664fee6
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/FiraSans-Italic.woff2
Binary files differdiff --git a/src/librustdoc/html/static/fonts/FiraSans-MediumItalic.woff2 b/src/librustdoc/html/static/fonts/FiraSans-MediumItalic.woff2
new file mode 100755
index 00000000000..2d08f9f7d45
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/FiraSans-MediumItalic.woff2
Binary files differdiff --git a/src/librustdoc/html/static/fonts/SourceSerif4-Semibold.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceSerif4-Semibold.ttf.woff2
new file mode 100644
index 00000000000..dd55f4e95ec
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/SourceSerif4-Semibold.ttf.woff2
Binary files differdiff --git a/src/librustdoc/html/static/js/README.md b/src/librustdoc/html/static/js/README.md
index 1fd859ad7cf..e99d7330f0e 100644
--- a/src/librustdoc/html/static/js/README.md
+++ b/src/librustdoc/html/static/js/README.md
@@ -3,13 +3,9 @@
 These JavaScript files are incorporated into the rustdoc binary at build time,
 and are minified and written to the filesystem as part of the doc build process.
 
-We use the [Closure Compiler](https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler)
+We use the [TypeScript Compiler](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
 dialect of JSDoc to comment our code and annotate params and return types.
 To run a check:
 
-    ./x.py doc library/std
-    npm i -g google-closure-compiler
-    google-closure-compiler -W VERBOSE \
-      build/<YOUR PLATFORM>/doc/{search-index*.js,crates*.js} \
-      src/librustdoc/html/static/js/{search.js,main.js,storage.js} \
-      --externs src/librustdoc/html/static/js/externs.js >/dev/null
+    npm i -g typescript
+    tsc --project tsconfig.json
diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js
deleted file mode 100644
index c4faca1c0c3..00000000000
--- a/src/librustdoc/html/static/js/externs.js
+++ /dev/null
@@ -1,270 +0,0 @@
-// This file contains type definitions that are processed by the Closure Compiler but are
-// not put into the JavaScript we include as part of the documentation. It is used for
-// type checking. See README.md in this directory for more info.
-
-/* eslint-disable */
-let searchState;
-function initSearch(searchIndex){}
-
-/**
- * @typedef {{
- *     name: string,
- *     id: number|null,
- *     fullPath: Array<string>,
- *     pathWithoutLast: Array<string>,
- *     pathLast: string,
- *     generics: Array<QueryElement>,
- *     bindings: Map<number, Array<QueryElement>>,
- * }}
- */
-let QueryElement;
-
-/**
- * @typedef {{
- *      pos: number,
- *      totalElems: number,
- *      typeFilter: (null|string),
- *      userQuery: string,
- *      isInBinding: (null|string),
- * }}
- */
-let ParserState;
-
-/**
- * @typedef {{
- *     original: string,
- *     userQuery: string,
- *     typeFilter: number,
- *     elems: Array<QueryElement>,
- *     args: Array<QueryElement>,
- *     returned: Array<QueryElement>,
- *     foundElems: number,
- *     totalElems: number,
- *     literalSearch: boolean,
- *     hasReturnArrow: boolean,
- *     corrections: Array<{from: string, to: integer}> | null,
- *     typeFingerprint: Uint32Array,
- *     error: Array<string> | null,
- * }}
- */
-let ParsedQuery;
-
-/**
- * @typedef {{
- *    crate: string,
- *    desc: string,
- *    id: number,
- *    name: string,
- *    normalizedName: string,
- *    parent: (Object|null|undefined),
- *    path: string,
- *    ty: (Number|null|number),
- *    type: FunctionSearchType?
- * }}
- */
-let Row;
-
-/**
- * @typedef {{
- *    in_args: Array<Object>,
- *    returned: Array<Object>,
- *    others: Array<Object>,
- *    query: ParsedQuery,
- * }}
- */
-let ResultsTable;
-
-/**
- * @typedef {Map<String, ResultObject>}
- */
-let Results;
-
-/**
- * @typedef {{
- *     desc: string,
- *     displayPath: string,
- *     fullPath: string,
- *     href: string,
- *     id: number,
- *     lev: number,
- *     name: string,
- *     normalizedName: string,
- *     parent: (Object|undefined),
- *     path: string,
- *     ty: number,
- *     type: FunctionSearchType?,
- *     displayType: Promise<Array<Array<string>>>|null,
- *     displayTypeMappedNames: Promise<Array<[string, Array<string>]>>|null,
- * }}
- */
-let ResultObject;
-
-/**
- * A pair of [inputs, outputs], or 0 for null. This is stored in the search index.
- * The JavaScript deserializes this into FunctionSearchType.
- *
- * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
- * because `null` is four bytes while `0` is one byte.
- *
- * An input or output can be encoded as just a number if there is only one of them, AND
- * it has no generics. The no generics rule exists to avoid ambiguity: imagine if you had
- * a function with a single output, and that output had a single generic:
- *
- *     fn something() -> Result<usize, usize>
- *
- * If output was allowed to be any RawFunctionType, it would look like thi
- *
- *     [[], [50, [3, 3]]]
- *
- * The problem is that the above output could be interpreted as either a type with ID 50 and two
- * generics, or it could be interpreted as a pair of types, the first one with ID 50 and the second
- * with ID 3 and a single generic parameter that is also ID 3. We avoid this ambiguity by choosing
- * in favor of the pair of types interpretation. This is why the `(number|Array<RawFunctionType>)`
- * is used instead of `(RawFunctionType|Array<RawFunctionType>)`.
- *
- * The output can be skipped if it's actually unit and there's no type constraints. If thi
- * function accepts constrained generics, then the output will be unconditionally emitted, and
- * after it will come a list of trait constraints. The position of the item in the list will
- * determine which type parameter it is. For example:
- *
- *     [1, 2, 3, 4, 5]
- *      ^  ^  ^  ^  ^
- *      |  |  |  |  - generic parameter (-3) of trait 5
- *      |  |  |  - generic parameter (-2) of trait 4
- *      |  |  - generic parameter (-1) of trait 3
- *      |  - this function returns a single value (type 2)
- *      - this function takes a single input parameter (type 1)
- *
- * Or, for a less contrived version:
- *
- *     [[[4, -1], 3], [[5, -1]], 11]
- *      -^^^^^^^----   ^^^^^^^   ^^
- *       |        |    |          - generic parameter, roughly `where -1: 11`
- *       |        |    |            since -1 is the type parameter and 11 the trait
- *       |        |    - function output 5<-1>
- *       |        - the overall function signature is something like
- *       |          `fn(4<-1>, 3) -> 5<-1> where -1: 11`
- *       - function input, corresponds roughly to 4<-1>
- *         4 is an index into the `p` array for a type
- *         -1 is the generic parameter, given by 11
- *
- * If a generic parameter has multiple trait constraints, it gets wrapped in an array, just like
- * function inputs and outputs:
- *
- *     [-1, -1, [4, 3]]
- *              ^^^^^^ where -1: 4 + 3
- *
- * If a generic parameter's trait constraint has generic parameters, it gets wrapped in the array
- * even if only one exists. In other words, the ambiguity of `4<3>` and `4 + 3` is resolved in
- * favor of `4 + 3`:
- *
- *     [-1, -1, [[4, 3]]]
- *              ^^^^^^^^ where -1: 4 + 3
- *
- *     [-1, -1, [5, [4, 3]]]
- *              ^^^^^^^^^^^ where -1: 5, -2: 4 + 3
- *
- * If a generic parameter has no trait constraints (like in Rust, the `Sized` constraint i
- * implied and a fake `?Sized` constraint used to note its absence), it will be filled in with 0.
- *
- * @typedef {(
- *     0 |
- *     [(number|Array<RawFunctionType>)] |
- *     [(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)] |
- *     Array<(number|Array<RawFunctionType>)>
- * )}
- */
-let RawFunctionSearchType;
-
-/**
- * A single function input or output type. This is either a single path ID, or a pair of
- * [path ID, generics].
- *
- * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
- * because `null` is four bytes while `0` is one byte.
- *
- * @typedef {number | [number, Array<RawFunctionType>]}
- */
-let RawFunctionType;
-
-/**
- * @typedef {{
- *     inputs: Array<FunctionType>,
- *     output: Array<FunctionType>,
- *     where_clause: Array<Array<FunctionType>>,
- * }}
- */
-let FunctionSearchType;
-
-/**
- * @typedef {{
- *     id: (null|number),
- *     ty: number,
- *     generics: Array<FunctionType>,
- *     bindings: Map<integer, Array<FunctionType>>,
- * }}
- */
-let FunctionType;
-
-/**
- * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f`
- * are arrays with the same length. `q`, `a`, and `c` use a sparse
- * representation for compactness.
- *
- * `n[i]` contains the name of an item.
- *
- * `t[i]` contains the type of that item
- * (as a string of characters that represent an offset in `itemTypes`).
- *
- * `d[i]` contains the description of that item.
- *
- * `q` contains the full paths of the items. For compactness, it is a set of
- * (index, path) pairs used to create a map. If a given index `i` is
- * not present, this indicates "same as the last index present".
- *
- * `i[i]` contains an item's parent, usually a module. For compactness,
- * it is a set of indexes into the `p` array.
- *
- * `f` contains function signatures, or `0` if the item isn't a function.
- * More information on how they're encoded can be found in rustc-dev-guide
- *
- * Functions are themselves encoded as arrays. The first item is a list of
- * types representing the function's inputs, and the second list item is a list
- * of types representing the function's output. Tuples are flattened.
- * Types are also represented as arrays; the first item is an index into the `p`
- * array, while the second is a list of types representing any generic parameters.
- *
- * b[i] contains an item's impl disambiguator. This is only present if an item
- * is defined in an impl block and, the impl block's type has more than one associated
- * item with the same name.
- *
- * `a` defines aliases with an Array of pairs: [name, offset], where `offset`
- * points into the n/t/d/q/i/f arrays.
- *
- * `doc` contains the description of the crate.
- *
- * `p` is a list of path/type pairs. It is used for parents and function parameters.
- * The first item is the type, the second is the name, the third is the visible path (if any) and
- * the fourth is the canonical path used for deduplication (if any).
- *
- * `r` is the canonical path used for deduplication of re-exported items.
- * It is not used for associated items like methods (that's the fourth element
- * of `p`) but is used for modules items like free functions.
- *
- * `c` is an array of item indices that are deprecated.
- * @typedef {{
- *   doc: string,
- *   a: Object,
- *   n: Array<string>,
- *   t: string,
- *   d: Array<string>,
- *   q: Array<[number, string]>,
- *   i: Array<number>,
- *   f: string,
- *   p: Array<[number, string] | [number, string, number] | [number, string, number, number]>,
- *   b: Array<[number, String]>,
- *   c: Array<number>,
- *   r: Array<[number, number]>,
- * }}
- */
-let RawSearchIndexCrate;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 984b0877d8d..ccf4002bb30 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -11,8 +11,13 @@
 window.RUSTDOC_TOOLTIP_HOVER_MS = 300;
 window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS = 450;
 
-// Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
-// for a resource under the root-path, with the resource-suffix.
+/**
+ * Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
+ * for a resource under the root-path, with the resource-suffix.
+ *
+ * @param {string} basename
+ * @param {string} extension
+ */
 function resourcePath(basename, extension) {
     return getVar("root-path") + basename + getVar("resource-suffix") + extension;
 }
@@ -27,13 +32,18 @@ function hideMain() {
 
 function showMain() {
     const main = document.getElementById(MAIN_ID);
+    if (!main) {
+        return;
+    }
     removeClass(main, "hidden");
     const mainHeading = main.querySelector(".main-heading");
-    if (mainHeading && searchState.rustdocToolbar) {
-        if (searchState.rustdocToolbar.parentElement) {
-            searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
+    if (mainHeading && window.searchState.rustdocToolbar) {
+        if (window.searchState.rustdocToolbar.parentElement) {
+            window.searchState.rustdocToolbar.parentElement.removeChild(
+                window.searchState.rustdocToolbar,
+            );
         }
-        mainHeading.appendChild(searchState.rustdocToolbar);
+        mainHeading.appendChild(window.searchState.rustdocToolbar);
     }
     const toggle = document.getElementById("toggle-all-docs");
     if (toggle) {
@@ -61,16 +71,20 @@ function setMobileTopbar() {
     }
 }
 
-// Gets the human-readable string for the virtual-key code of the
-// given KeyboardEvent, ev.
-//
-// This function is meant as a polyfill for KeyboardEvent#key,
-// since it is not supported in IE 11 or Chrome for Android. We also test for
-// KeyboardEvent#keyCode because the handleShortcut handler is
-// also registered for the keydown event, because Blink doesn't fire
-// keypress on hitting the Escape key.
-//
-// So I guess you could say things are getting pretty interoperable.
+/**
+ * Gets the human-readable string for the virtual-key code of the
+ * given KeyboardEvent, ev.
+ *
+ * This function is meant as a polyfill for KeyboardEvent#key,
+ * since it is not supported in IE 11 or Chrome for Android. We also test for
+ * KeyboardEvent#keyCode because the handleShortcut handler is
+ * also registered for the keydown event, because Blink doesn't fire
+ * keypress on hitting the Escape key.
+ *
+ * So I guess you could say things are getting pretty interoperable.
+ *
+ * @param {KeyboardEvent} ev
+ */
 function getVirtualKey(ev) {
     if ("key" in ev && typeof ev.key !== "undefined") {
         return ev.key;
@@ -110,6 +124,9 @@ function getNakedUrl() {
  * @param {HTMLElement} referenceNode
  */
 function insertAfter(newNode, referenceNode) {
+    // You're not allowed to pass an element with no parent.
+    // I dunno how to make TS's typechecker see that.
+    // @ts-expect-error
     referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
 }
 
@@ -129,6 +146,7 @@ function getOrCreateSection(id, classes) {
         el = document.createElement("section");
         el.id = id;
         el.className = classes;
+        // @ts-expect-error
         insertAfter(el, document.getElementById(MAIN_ID));
     }
     return el;
@@ -159,12 +177,13 @@ function getNotDisplayedElem() {
  * contains the displayed element (there can be only one at the same time!). So basically, we switch
  * elements between the two `<section>` elements.
  *
- * @param {HTMLElement} elemToDisplay
+ * @param {HTMLElement|null} elemToDisplay
  */
 function switchDisplayedElement(elemToDisplay) {
     const el = getAlternativeDisplayElem();
 
     if (el.children.length > 0) {
+        // @ts-expect-error
         getNotDisplayedElem().appendChild(el.firstElementChild);
     }
     if (elemToDisplay === null) {
@@ -177,10 +196,14 @@ function switchDisplayedElement(elemToDisplay) {
     removeClass(el, "hidden");
 
     const mainHeading = elemToDisplay.querySelector(".main-heading");
+    // @ts-expect-error
     if (mainHeading && searchState.rustdocToolbar) {
+        // @ts-expect-error
         if (searchState.rustdocToolbar.parentElement) {
+            // @ts-expect-error
             searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
         }
+        // @ts-expect-error
         mainHeading.appendChild(searchState.rustdocToolbar);
     }
 }
@@ -189,6 +212,7 @@ function browserSupportsHistoryApi() {
     return window.history && typeof window.history.pushState === "function";
 }
 
+// @ts-expect-error
 function preLoadCss(cssUrl) {
     // https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload
     const link = document.createElement("link");
@@ -201,6 +225,7 @@ function preLoadCss(cssUrl) {
 (function() {
     const isHelpPage = window.location.pathname.endsWith("/help.html");
 
+    // @ts-expect-error
     function loadScript(url, errorCallback) {
         const script = document.createElement("script");
         script.src = url;
@@ -211,21 +236,25 @@ function preLoadCss(cssUrl) {
     }
 
     if (getSettingsButton()) {
+        // @ts-expect-error
         getSettingsButton().onclick = event => {
             if (event.ctrlKey || event.altKey || event.metaKey) {
                 return;
             }
+            // @ts-expect-error
             window.hideAllModals(false);
             addClass(getSettingsButton(), "rotate");
             event.preventDefault();
             // Sending request for the CSS and the JS files at the same time so it will
             // hopefully be loaded when the JS will generate the settings content.
+            // @ts-expect-error
             loadScript(getVar("static-root-path") + getVar("settings-js"));
             // Pre-load all theme CSS files, so that switching feels seamless.
             //
             // When loading settings.html as a standalone page, the equivalent HTML is
             // generated in context.rs.
             setTimeout(() => {
+                // @ts-expect-error
                 const themes = getVar("themes").split(",");
                 for (const theme of themes) {
                     // if there are no themes, do nothing
@@ -241,6 +270,8 @@ function preLoadCss(cssUrl) {
     window.searchState = {
         rustdocToolbar: document.querySelector("rustdoc-toolbar"),
         loadingText: "Loading search results...",
+        // This will always be an HTMLInputElement, but tsc can't see that
+        // @ts-expect-error
         input: document.getElementsByClassName("search-input")[0],
         outputElement: () => {
             let el = document.getElementById("search");
@@ -263,31 +294,38 @@ function preLoadCss(cssUrl) {
         // tab and back preserves the element that was focused.
         focusedByTab: [null, null, null],
         clearInputTimeout: () => {
-            if (searchState.timeout !== null) {
-                clearTimeout(searchState.timeout);
-                searchState.timeout = null;
+            if (window.searchState.timeout !== null) {
+                clearTimeout(window.searchState.timeout);
+                window.searchState.timeout = null;
             }
         },
-        isDisplayed: () => searchState.outputElement().parentElement.id === ALTERNATIVE_DISPLAY_ID,
+        // @ts-expect-error
+        isDisplayed: () => {
+            const outputElement = window.searchState.outputElement();
+            return outputElement &&
+                outputElement.parentElement &&
+                outputElement.parentElement.id === ALTERNATIVE_DISPLAY_ID;
+        },
         // Sets the focus on the search bar at the top of the page
         focus: () => {
-            searchState.input.focus();
+            window.searchState.input && window.searchState.input.focus();
         },
         // Removes the focus from the search bar.
         defocus: () => {
-            searchState.input.blur();
+            window.searchState.input && window.searchState.input.blur();
         },
         showResults: search => {
             if (search === null || typeof search === "undefined") {
-                search = searchState.outputElement();
+                search = window.searchState.outputElement();
             }
             switchDisplayedElement(search);
-            searchState.mouseMovedAfterSearch = false;
-            document.title = searchState.title;
+            // @ts-expect-error
+            window.searchState.mouseMovedAfterSearch = false;
+            document.title = window.searchState.title;
         },
         removeQueryParameters: () => {
             // We change the document title.
-            document.title = searchState.titleBeforeSearch;
+            document.title = window.searchState.titleBeforeSearch;
             if (browserSupportsHistoryApi()) {
                 history.replaceState(null, "", getNakedUrl() + window.location.hash);
             }
@@ -295,9 +333,10 @@ function preLoadCss(cssUrl) {
         hideResults: () => {
             switchDisplayedElement(null);
             // We also remove the query parameter from the URL.
-            searchState.removeQueryParameters();
+            window.searchState.removeQueryParameters();
         },
         getQueryStringParams: () => {
+            /** @type {Object.<any, string>} */
             const params = {};
             window.location.search.substring(1).split("&").
                 map(s => {
@@ -309,26 +348,28 @@ function preLoadCss(cssUrl) {
             return params;
         },
         setup: () => {
-            const search_input = searchState.input;
-            if (!searchState.input) {
+            const search_input = window.searchState.input;
+            if (!search_input) {
                 return;
             }
             let searchLoaded = false;
             // If you're browsing the nightly docs, the page might need to be refreshed for the
             // search to work because the hash of the JS scripts might have changed.
             function sendSearchForm() {
+                // @ts-expect-error
                 document.getElementsByClassName("search-form")[0].submit();
             }
             function loadSearch() {
                 if (!searchLoaded) {
                     searchLoaded = true;
+                    // @ts-expect-error
                     loadScript(getVar("static-root-path") + getVar("search-js"), sendSearchForm);
                     loadScript(resourcePath("search-index", ".js"), sendSearchForm);
                 }
             }
 
             search_input.addEventListener("focus", () => {
-                search_input.origPlaceholder = search_input.placeholder;
+                window.searchState.origPlaceholder = search_input.placeholder;
                 search_input.placeholder = "Type your search here.";
                 loadSearch();
             });
@@ -337,16 +378,21 @@ function preLoadCss(cssUrl) {
                 loadSearch();
             }
 
-            const params = searchState.getQueryStringParams();
+            const params = window.searchState.getQueryStringParams();
             if (params.search !== undefined) {
-                searchState.setLoadingSearch();
+                window.searchState.setLoadingSearch();
                 loadSearch();
             }
         },
         setLoadingSearch: () => {
-            const search = searchState.outputElement();
-            search.innerHTML = "<h3 class=\"search-loading\">" + searchState.loadingText + "</h3>";
-            searchState.showResults(search);
+            const search = window.searchState.outputElement();
+            if (!search) {
+                return;
+            }
+            search.innerHTML = "<h3 class=\"search-loading\">" +
+                window.searchState.loadingText +
+                "</h3>";
+            window.searchState.showResults(search);
         },
         descShards: new Map(),
         loadDesc: async function({descShard, descIndex}) {
@@ -370,6 +416,8 @@ function preLoadCss(cssUrl) {
             return list[descIndex];
         },
         loadedDescShard: function(crate, shard, data) {
+            // If loadedDescShard gets called, then the library must have been declared.
+            // @ts-expect-error
             this.descShards.get(crate)[shard].resolve(data.split("\n"));
         },
     };
@@ -377,8 +425,11 @@ function preLoadCss(cssUrl) {
     const toggleAllDocsId = "toggle-all-docs";
     let savedHash = "";
 
+    /**
+     * @param {HashChangeEvent|null} ev
+     */
     function handleHashes(ev) {
-        if (ev !== null && searchState.isDisplayed() && ev.newURL) {
+        if (ev !== null && window.searchState.isDisplayed() && ev.newURL) {
             // This block occurs when clicking on an element in the navbar while
             // in a search.
             switchDisplayedElement(null);
@@ -419,6 +470,7 @@ function preLoadCss(cssUrl) {
                     }
                     return onEachLazy(implElem.parentElement.parentElement.querySelectorAll(
                         `[id^="${assocId}"]`),
+                        // @ts-expect-error
                         item => {
                             const numbered = /^(.+?)-([0-9]+)$/.exec(item.id);
                             if (item.id === assocId || (numbered && numbered[1] === assocId)) {
@@ -437,12 +489,16 @@ function preLoadCss(cssUrl) {
         }
     }
 
+    /**
+     * @param {HashChangeEvent|null} ev
+     */
     function onHashChange(ev) {
         // If we're in mobile mode, we should hide the sidebar in any case.
         hideSidebar();
         handleHashes(ev);
     }
 
+    // @ts-expect-error
     function openParentDetails(elem) {
         while (elem) {
             if (elem.tagName === "DETAILS") {
@@ -452,18 +508,25 @@ function preLoadCss(cssUrl) {
         }
     }
 
+    // @ts-expect-error
     function expandSection(id) {
         openParentDetails(document.getElementById(id));
     }
 
+    // @ts-expect-error
     function handleEscape(ev) {
+        // @ts-expect-error
         searchState.clearInputTimeout();
+        // @ts-expect-error
         searchState.hideResults();
         ev.preventDefault();
+        // @ts-expect-error
         searchState.defocus();
+        // @ts-expect-error
         window.hideAllModals(true); // true = reset focus for tooltips
     }
 
+    // @ts-expect-error
     function handleShortcut(ev) {
         // Don't interfere with browser shortcuts
         const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
@@ -471,8 +534,11 @@ function preLoadCss(cssUrl) {
             return;
         }
 
+        // @ts-expect-error
         if (document.activeElement.tagName === "INPUT" &&
+            // @ts-expect-error
             document.activeElement.type !== "checkbox" &&
+            // @ts-expect-error
             document.activeElement.type !== "radio") {
             switch (getVirtualKey(ev)) {
             case "Escape":
@@ -489,6 +555,7 @@ function preLoadCss(cssUrl) {
             case "S":
             case "/":
                 ev.preventDefault();
+                // @ts-expect-error
                 searchState.focus();
                 break;
 
@@ -515,6 +582,7 @@ function preLoadCss(cssUrl) {
     document.addEventListener("keydown", handleShortcut);
 
     function addSidebarItems() {
+        // @ts-expect-error
         if (!window.SIDEBAR_ITEMS) {
             return;
         }
@@ -529,6 +597,7 @@ function preLoadCss(cssUrl) {
          *                          "Modules", or "Macros".
          */
         function block(shortty, id, longty) {
+            // @ts-expect-error
             const filtered = window.SIDEBAR_ITEMS[shortty];
             if (!filtered) {
                 return;
@@ -564,7 +633,9 @@ function preLoadCss(cssUrl) {
                 li.appendChild(link);
                 ul.appendChild(li);
             }
+            // @ts-expect-error
             sidebar.appendChild(h3);
+            // @ts-expect-error
             sidebar.appendChild(ul);
         }
 
@@ -600,6 +671,7 @@ function preLoadCss(cssUrl) {
     }
 
     // <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+trait.impl&type=code>
+    // @ts-expect-error
     window.register_implementors = imp => {
         const implementors = document.getElementById("implementors-list");
         const synthetic_implementors = document.getElementById("synthetic-implementors-list");
@@ -615,18 +687,22 @@ function preLoadCss(cssUrl) {
             //
             // By the way, this is only used by and useful for traits implemented automatically
             // (like "Send" and "Sync").
+            // @ts-expect-error
             onEachLazy(synthetic_implementors.getElementsByClassName("impl"), el => {
                 const aliases = el.getAttribute("data-aliases");
                 if (!aliases) {
                     return;
                 }
+                // @ts-expect-error
                 aliases.split(",").forEach(alias => {
                     inlined_types.add(alias);
                 });
             });
         }
 
+        // @ts-expect-error
         let currentNbImpls = implementors.getElementsByClassName("impl").length;
+        // @ts-expect-error
         const traitName = document.querySelector(".main-heading h1 > .trait").textContent;
         const baseIdName = "impl-" + traitName + "-";
         const libs = Object.getOwnPropertyNames(imp);
@@ -636,6 +712,7 @@ function preLoadCss(cssUrl) {
         const script = document
             .querySelector("script[data-ignore-extern-crates]");
         const ignoreExternCrates = new Set(
+            // @ts-expect-error
             (script ? script.getAttribute("data-ignore-extern-crates") : "").split(","),
         );
         for (const lib of libs) {
@@ -663,6 +740,7 @@ function preLoadCss(cssUrl) {
                 code.innerHTML = struct[TEXT_IDX];
                 addClass(code, "code-header");
 
+                // @ts-expect-error
                 onEachLazy(code.getElementsByTagName("a"), elem => {
                     const href = elem.getAttribute("href");
 
@@ -681,12 +759,15 @@ function preLoadCss(cssUrl) {
                 addClass(display, "impl");
                 display.appendChild(anchor);
                 display.appendChild(code);
+                // @ts-expect-error
                 list.appendChild(display);
                 currentNbImpls += 1;
             }
         }
     };
+    // @ts-expect-error
     if (window.pending_implementors) {
+        // @ts-expect-error
         window.register_implementors(window.pending_implementors);
     }
 
@@ -719,12 +800,15 @@ function preLoadCss(cssUrl) {
      *
      * - After processing all of the impls, it sorts the sidebar items by name.
      *
-     * @param {{[cratename: string]: Array<Array<string|0>>}} impl
+     * @param {{[cratename: string]: Array<Array<string|0>>}} imp
      */
+    // @ts-expect-error
     window.register_type_impls = imp => {
+        // @ts-expect-error
         if (!imp || !imp[window.currentCrate]) {
             return;
         }
+        // @ts-expect-error
         window.pending_type_impls = null;
         const idMap = new Map();
 
@@ -744,6 +828,7 @@ function preLoadCss(cssUrl) {
         let associatedConstants = document.querySelector(".sidebar .block.associatedconstant");
         let sidebarTraitList = document.querySelector(".sidebar .block.trait-implementation");
 
+        // @ts-expect-error
         for (const impList of imp[window.currentCrate]) {
             const types = impList.slice(2);
             const text = impList[0];
@@ -772,20 +857,28 @@ function preLoadCss(cssUrl) {
                     h.appendChild(link);
                     trait_implementations = outputList;
                     trait_implementations_header = outputListHeader;
+                    // @ts-expect-error
                     sidebarSection.appendChild(h);
                     sidebarTraitList = document.createElement("ul");
                     sidebarTraitList.className = "block trait-implementation";
+                    // @ts-expect-error
                     sidebarSection.appendChild(sidebarTraitList);
+                    // @ts-expect-error
                     mainContent.appendChild(outputListHeader);
+                    // @ts-expect-error
                     mainContent.appendChild(outputList);
                 } else {
                     implementations = outputList;
                     if (trait_implementations) {
+                        // @ts-expect-error
                         mainContent.insertBefore(outputListHeader, trait_implementations_header);
+                        // @ts-expect-error
                         mainContent.insertBefore(outputList, trait_implementations_header);
                     } else {
                         const mainContent = document.querySelector("#main-content");
+                        // @ts-expect-error
                         mainContent.appendChild(outputListHeader);
+                        // @ts-expect-error
                         mainContent.appendChild(outputList);
                     }
                 }
@@ -793,6 +886,7 @@ function preLoadCss(cssUrl) {
             const template = document.createElement("template");
             template.innerHTML = text;
 
+            // @ts-expect-error
             onEachLazy(template.content.querySelectorAll("a"), elem => {
                 const href = elem.getAttribute("href");
 
@@ -800,6 +894,7 @@ function preLoadCss(cssUrl) {
                     elem.setAttribute("href", window.rootPath + href);
                 }
             });
+            // @ts-expect-error
             onEachLazy(template.content.querySelectorAll("[id]"), el => {
                 let i = 0;
                 if (idMap.has(el.id)) {
@@ -817,6 +912,7 @@ function preLoadCss(cssUrl) {
                     const oldHref = `#${el.id}`;
                     const newHref = `#${el.id}-${i}`;
                     el.id = `${el.id}-${i}`;
+                    // @ts-expect-error
                     onEachLazy(template.content.querySelectorAll("a[href]"), link => {
                         if (link.getAttribute("href") === oldHref) {
                             link.href = newHref;
@@ -830,11 +926,14 @@ function preLoadCss(cssUrl) {
             if (isTrait) {
                 const li = document.createElement("li");
                 const a = document.createElement("a");
+                // @ts-expect-error
                 a.href = `#${template.content.querySelector(".impl").id}`;
                 a.textContent = traitName;
                 li.appendChild(a);
+                // @ts-expect-error
                 sidebarTraitList.append(li);
             } else {
+                // @ts-expect-error
                 onEachLazy(templateAssocItems, item => {
                     let block = hasClass(item, "associatedtype") ? associatedTypes : (
                         hasClass(item, "associatedconstant") ? associatedConstants : (
@@ -856,10 +955,14 @@ function preLoadCss(cssUrl) {
                         const insertionReference = methods || sidebarTraitList;
                         if (insertionReference) {
                             const insertionReferenceH = insertionReference.previousElementSibling;
+                            // @ts-expect-error
                             sidebarSection.insertBefore(blockHeader, insertionReferenceH);
+                            // @ts-expect-error
                             sidebarSection.insertBefore(block, insertionReferenceH);
                         } else {
+                            // @ts-expect-error
                             sidebarSection.appendChild(blockHeader);
+                            // @ts-expect-error
                             sidebarSection.appendChild(block);
                         }
                         if (hasClass(item, "associatedtype")) {
@@ -896,11 +999,14 @@ function preLoadCss(cssUrl) {
             list.replaceChildren(...newChildren);
         }
     };
+    // @ts-expect-error
     if (window.pending_type_impls) {
+        // @ts-expect-error
         window.register_type_impls(window.pending_type_impls);
     }
 
     function addSidebarCrates() {
+        // @ts-expect-error
         if (!window.ALL_CRATES) {
             return;
         }
@@ -914,6 +1020,7 @@ function preLoadCss(cssUrl) {
         const ul = document.createElement("ul");
         ul.className = "block crate";
 
+        // @ts-expect-error
         for (const crate of window.ALL_CRATES) {
             const link = document.createElement("a");
             link.href = window.rootPath + crate + "/index.html";
@@ -933,17 +1040,20 @@ function preLoadCss(cssUrl) {
     function expandAllDocs() {
         const innerToggle = document.getElementById(toggleAllDocsId);
         removeClass(innerToggle, "will-expand");
+        // @ts-expect-error
         onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) {
                 e.open = true;
             }
         });
+        // @ts-expect-error
         innerToggle.children[0].innerText = "Summary";
     }
 
     function collapseAllDocs() {
         const innerToggle = document.getElementById(toggleAllDocsId);
         addClass(innerToggle, "will-expand");
+        // @ts-expect-error
         onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (e.parentNode.id !== "implementations-list" ||
                 (!hasClass(e, "implementors-toggle") &&
@@ -952,6 +1062,7 @@ function preLoadCss(cssUrl) {
                 e.open = false;
             }
         });
+        // @ts-expect-error
         innerToggle.children[0].innerText = "Show all";
     }
 
@@ -977,9 +1088,11 @@ function preLoadCss(cssUrl) {
         const hideImplementations = getSettingValue("auto-hide-trait-implementations") === "true";
         const hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
 
+        // @ts-expect-error
         function setImplementorsTogglesOpen(id, open) {
             const list = document.getElementById(id);
             if (list !== null) {
+                // @ts-expect-error
                 onEachLazy(list.getElementsByClassName("implementors-toggle"), e => {
                     e.open = open;
                 });
@@ -991,6 +1104,7 @@ function preLoadCss(cssUrl) {
             setImplementorsTogglesOpen("blanket-implementations-list", false);
         }
 
+        // @ts-expect-error
         onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {
                 e.open = true;
@@ -1002,6 +1116,7 @@ function preLoadCss(cssUrl) {
         });
     }());
 
+    // @ts-expect-error
     window.rustdoc_add_line_numbers_to_examples = () => {
         if (document.querySelector(".rustdoc.src")) {
             // We are in the source code page, nothing to be done here!
@@ -1009,6 +1124,7 @@ function preLoadCss(cssUrl) {
         }
         onEachLazy(document.querySelectorAll(
             ":not(.scraped-example) > .example-wrap > pre:not(.example-line-numbers)",
+        // @ts-expect-error
         ), x => {
             const parent = x.parentNode;
             const line_numbers = parent.querySelectorAll(".example-line-numbers");
@@ -1027,33 +1143,41 @@ function preLoadCss(cssUrl) {
         });
     };
 
+    // @ts-expect-error
     window.rustdoc_remove_line_numbers_from_examples = () => {
+        // @ts-expect-error
         onEachLazy(document.querySelectorAll(".example-wrap > .example-line-numbers"), x => {
             x.parentNode.removeChild(x);
         });
     };
 
     if (getSettingValue("line-numbers") === "true") {
+        // @ts-expect-error
         window.rustdoc_add_line_numbers_to_examples();
     }
 
     function showSidebar() {
+        // @ts-expect-error
         window.hideAllModals(false);
         const sidebar = document.getElementsByClassName("sidebar")[0];
+        // @ts-expect-error
         addClass(sidebar, "shown");
     }
 
     function hideSidebar() {
         const sidebar = document.getElementsByClassName("sidebar")[0];
+        // @ts-expect-error
         removeClass(sidebar, "shown");
     }
 
     window.addEventListener("resize", () => {
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT) {
             // As a workaround to the behavior of `contains: layout` used in doc togglers,
             // tooltip popovers are positioned using javascript.
             //
             // This means when the window is resized, we need to redo the layout.
+            // @ts-expect-error
             const base = window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;
             const force_visible = base.TOOLTIP_FORCE_VISIBLE;
             hideTooltip(false);
@@ -1069,6 +1193,7 @@ function preLoadCss(cssUrl) {
         mainElem.addEventListener("click", hideSidebar);
     }
 
+    // @ts-expect-error
     onEachLazy(document.querySelectorAll("a[href^='#']"), el => {
         // For clicks on internal links (<A> tags with a hash property), we expand the section we're
         // jumping to *before* jumping there. We can't do this in onHashChange, because it changes
@@ -1079,7 +1204,9 @@ function preLoadCss(cssUrl) {
         });
     });
 
+    // @ts-expect-error
     onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => {
+        // @ts-expect-error
         el.addEventListener("click", e => {
             if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") {
                 e.preventDefault();
@@ -1090,15 +1217,17 @@ function preLoadCss(cssUrl) {
     /**
      * Show a tooltip immediately.
      *
-     * @param {DOMElement} e - The tooltip's anchor point. The DOM is consulted to figure
-     *                         out what the tooltip should contain, and where it should be
-     *                         positioned.
+     * @param {HTMLElement} e - The tooltip's anchor point. The DOM is consulted to figure
+     *                          out what the tooltip should contain, and where it should be
+     *                          positioned.
      */
     function showTooltip(e) {
         const notable_ty = e.getAttribute("data-notable-ty");
+        // @ts-expect-error
         if (!window.NOTABLE_TRAITS && notable_ty) {
             const data = document.getElementById("notable-traits-data");
             if (data) {
+                // @ts-expect-error
                 window.NOTABLE_TRAITS = JSON.parse(data.innerText);
             } else {
                 throw new Error("showTooltip() called with notable without any notable traits!");
@@ -1106,36 +1235,44 @@ function preLoadCss(cssUrl) {
         }
         // Make this function idempotent. If the tooltip is already shown, avoid doing extra work
         // and leave it alone.
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) {
+            // @ts-expect-error
             clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
             return;
         }
+        // @ts-expect-error
         window.hideAllModals(false);
         const wrapper = document.createElement("div");
         if (notable_ty) {
             wrapper.innerHTML = "<div class=\"content\">" +
+                // @ts-expect-error
                 window.NOTABLE_TRAITS[notable_ty] + "</div>";
         } else {
             // Replace any `title` attribute with `data-title` to avoid double tooltips.
-            if (e.getAttribute("title") !== null) {
-                e.setAttribute("data-title", e.getAttribute("title"));
+            const ttl = e.getAttribute("title");
+            if (ttl !== null) {
+                e.setAttribute("data-title", ttl);
                 e.removeAttribute("title");
             }
-            if (e.getAttribute("data-title") !== null) {
+            const dttl = e.getAttribute("data-title");
+            if (dttl !== null) {
                 const titleContent = document.createElement("div");
                 titleContent.className = "content";
-                titleContent.appendChild(document.createTextNode(e.getAttribute("data-title")));
+                titleContent.appendChild(document.createTextNode(dttl));
                 wrapper.appendChild(titleContent);
             }
         }
         wrapper.className = "tooltip popover";
         const focusCatcher = document.createElement("div");
         focusCatcher.setAttribute("tabindex", "0");
+        // @ts-expect-error
         focusCatcher.onfocus = hideTooltip;
         wrapper.appendChild(focusCatcher);
         const pos = e.getBoundingClientRect();
         // 5px overlap so that the mouse can easily travel from place to place
         wrapper.style.top = (pos.top + window.scrollY + pos.height) + "px";
+        // @ts-expect-error
         wrapper.style.left = 0;
         wrapper.style.right = "auto";
         wrapper.style.visibility = "hidden";
@@ -1152,8 +1289,11 @@ function preLoadCss(cssUrl) {
             );
         }
         wrapper.style.visibility = "";
+        // @ts-expect-error
         window.CURRENT_TOOLTIP_ELEMENT = wrapper;
+        // @ts-expect-error
         window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e;
+        // @ts-expect-error
         clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
         wrapper.onpointerenter = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
@@ -1164,7 +1304,7 @@ function preLoadCss(cssUrl) {
         };
         wrapper.onpointerleave = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
-            if (ev.pointerType !== "mouse") {
+            if (ev.pointerType !== "mouse" || !(ev.relatedTarget instanceof HTMLElement)) {
                 return;
             }
             if (!e.TOOLTIP_FORCE_VISIBLE && !e.contains(ev.relatedTarget)) {
@@ -1180,23 +1320,27 @@ function preLoadCss(cssUrl) {
      * was called, that timeout gets cleared. If the tooltip is already in the requested state,
      * this function will still clear any pending timeout, but otherwise do nothing.
      *
-     * @param {DOMElement} element - The tooltip's anchor point. The DOM is consulted to figure
-     *                               out what the tooltip should contain, and where it should be
-     *                               positioned.
+     * @param {HTMLElement} element - The tooltip's anchor point. The DOM is consulted to figure
+     *                                out what the tooltip should contain, and where it should be
+     *                                positioned.
      * @param {boolean}    show    - If true, the tooltip will be made visible. If false, it will
      *                               be hidden.
      */
     function setTooltipHoverTimeout(element, show) {
         clearTooltipHoverTimeout(element);
+        // @ts-expect-error
         if (!show && !window.CURRENT_TOOLTIP_ELEMENT) {
             // To "hide" an already hidden element, just cancel its timeout.
             return;
         }
+        // @ts-expect-error
         if (show && window.CURRENT_TOOLTIP_ELEMENT) {
             // To "show" an already visible element, just cancel its timeout.
             return;
         }
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT &&
+            // @ts-expect-error
             window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE !== element) {
             // Don't do anything if another tooltip is already visible.
             return;
@@ -1214,22 +1358,29 @@ function preLoadCss(cssUrl) {
      * If a show/hide timeout was set by `setTooltipHoverTimeout`, cancel it. If none exists,
      * do nothing.
      *
-     * @param {DOMElement} element - The tooltip's anchor point,
-     *                               as passed to `setTooltipHoverTimeout`.
+     * @param {HTMLElement} element - The tooltip's anchor point,
+     *                                as passed to `setTooltipHoverTimeout`.
      */
     function clearTooltipHoverTimeout(element) {
         if (element.TOOLTIP_HOVER_TIMEOUT !== undefined) {
+            // @ts-expect-error
             removeClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out");
             clearTimeout(element.TOOLTIP_HOVER_TIMEOUT);
             delete element.TOOLTIP_HOVER_TIMEOUT;
         }
     }
 
+    // @ts-expect-error
     function tooltipBlurHandler(event) {
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT &&
+            // @ts-expect-error
             !window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement) &&
+            // @ts-expect-error
             !window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget) &&
+            // @ts-expect-error
             !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement) &&
+            // @ts-expect-error
             !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget)
         ) {
             // Work around a difference in the focus behaviour between Firefox, Chrome, and Safari.
@@ -1251,32 +1402,45 @@ function preLoadCss(cssUrl) {
      *                          If set to `false`, leave keyboard focus alone.
      */
     function hideTooltip(focus) {
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT) {
+            // @ts-expect-error
             if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) {
                 if (focus) {
+                    // @ts-expect-error
                     window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus();
                 }
+                // @ts-expect-error
                 window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false;
             }
+            // @ts-expect-error
             document.body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
+            // @ts-expect-error
             clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
+            // @ts-expect-error
             window.CURRENT_TOOLTIP_ELEMENT = null;
         }
     }
 
+    // @ts-expect-error
     onEachLazy(document.getElementsByClassName("tooltip"), e => {
         e.onclick = () => {
             e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true;
+            // @ts-expect-error
             if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) {
                 hideTooltip(true);
             } else {
                 showTooltip(e);
+                // @ts-expect-error
                 window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0");
+                // @ts-expect-error
                 window.CURRENT_TOOLTIP_ELEMENT.focus();
+                // @ts-expect-error
                 window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler;
             }
             return false;
         };
+        // @ts-expect-error
         e.onpointerenter = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
@@ -1284,6 +1448,7 @@ function preLoadCss(cssUrl) {
             }
             setTooltipHoverTimeout(e, true);
         };
+        // @ts-expect-error
         e.onpointermove = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
@@ -1291,12 +1456,15 @@ function preLoadCss(cssUrl) {
             }
             setTooltipHoverTimeout(e, true);
         };
+        // @ts-expect-error
         e.onpointerleave = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
+            // @ts-expect-error
             if (!e.TOOLTIP_FORCE_VISIBLE && window.CURRENT_TOOLTIP_ELEMENT &&
+                // @ts-expect-error
                 !window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)) {
                 // Tooltip pointer leave gesture:
                 //
@@ -1329,6 +1497,7 @@ function preLoadCss(cssUrl) {
                 // * https://www.nngroup.com/articles/tooltip-guidelines/
                 // * https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown
                 setTooltipHoverTimeout(e, false);
+                // @ts-expect-error
                 addClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out");
             }
         };
@@ -1338,6 +1507,7 @@ function preLoadCss(cssUrl) {
     if (sidebar_menu_toggle) {
         sidebar_menu_toggle.addEventListener("click", () => {
             const sidebar = document.getElementsByClassName("sidebar")[0];
+            // @ts-expect-error
             if (!hasClass(sidebar, "shown")) {
                 showSidebar();
             } else {
@@ -1346,12 +1516,18 @@ function preLoadCss(cssUrl) {
         });
     }
 
+    // @ts-expect-error
     function helpBlurHandler(event) {
+        // @ts-expect-error
         if (!getHelpButton().contains(document.activeElement) &&
+            // @ts-expect-error
             !getHelpButton().contains(event.relatedTarget) &&
+            // @ts-expect-error
             !getSettingsButton().contains(document.activeElement) &&
+            // @ts-expect-error
             !getSettingsButton().contains(event.relatedTarget)
         ) {
+            // @ts-expect-error
             window.hidePopoverMenus();
         }
     }
@@ -1427,14 +1603,18 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         if (isHelpPage) {
             const help_section = document.createElement("section");
             help_section.appendChild(container);
+            // @ts-expect-error
             document.getElementById("main-content").appendChild(help_section);
             container.style.display = "block";
         } else {
             const help_button = getHelpButton();
+            // @ts-expect-error
             help_button.appendChild(container);
 
             container.onblur = helpBlurHandler;
+            // @ts-expect-error
             help_button.onblur = helpBlurHandler;
+            // @ts-expect-error
             help_button.children[0].onblur = helpBlurHandler;
         }
 
@@ -1446,8 +1626,10 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
      *
      * Pass "true" to reset focus for tooltip popovers.
      */
+    // @ts-expect-error
     window.hideAllModals = switchFocus => {
         hideSidebar();
+        // @ts-expect-error
         window.hidePopoverMenus();
         hideTooltip(switchFocus);
     };
@@ -1455,7 +1637,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     /**
      * Hide all the popover menus.
      */
+    // @ts-expect-error
     window.hidePopoverMenus = () => {
+        // @ts-expect-error
         onEachLazy(document.querySelectorAll("rustdoc-toolbar .popover"), elem => {
             elem.style.display = "none";
         });
@@ -1474,10 +1658,12 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
      * @return {HTMLElement}
      */
     function getHelpMenu(buildNeeded) {
+        // @ts-expect-error
         let menu = getHelpButton().querySelector(".popover");
         if (!menu && buildNeeded) {
             menu = buildHelpMenu();
         }
+        // @ts-expect-error
         return menu;
     }
 
@@ -1489,9 +1675,11 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         // other modals.
         const button = getHelpButton();
         addClass(button, "help-open");
+        // @ts-expect-error
         button.querySelector("a").focus();
         const menu = getHelpMenu(true);
         if (menu.style.display === "none") {
+            // @ts-expect-error
             window.hideAllModals();
             menu.style.display = "";
         }
@@ -1506,8 +1694,11 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             // If user clicks with a moderator, though, use default browser behavior,
             // probably opening in a new window or tab.
             if (!helpLink.contains(helpLink) ||
+                // @ts-expect-error
                 event.ctrlKey ||
+                // @ts-expect-error
                 event.altKey ||
+                // @ts-expect-error
                 event.metaKey) {
                 return;
             }
@@ -1517,6 +1708,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             if (shouldShowHelp) {
                 showHelp();
             } else {
+                // @ts-expect-error
                 window.hidePopoverMenus();
             }
         });
@@ -1527,6 +1719,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     addSidebarCrates();
     onHashChange(null);
     window.addEventListener("hashchange", onHashChange);
+    // @ts-expect-error
     searchState.setup();
 }());
 
@@ -1580,6 +1773,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             removeClass(document.documentElement, "hide-sidebar");
             updateLocalStorage("hide-sidebar", "false");
             if (document.querySelector(".rustdoc.src")) {
+                // @ts-expect-error
                 window.rustdocToggleSrcSidebar();
             }
             e.preventDefault();
@@ -1589,6 +1783,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // Pointer capture.
     //
     // Resizing is a single-pointer gesture. Any secondary pointer is ignored
+    // @ts-expect-error
     let currentPointerId = null;
 
     // "Desired" sidebar size.
@@ -1596,6 +1791,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // This is stashed here for window resizing. If the sidebar gets
     // shrunk to maintain BODY_MIN, and then the user grows the window again,
     // it gets the sidebar to restore its size.
+    // @ts-expect-error
     let desiredSidebarSize = null;
 
     // Sidebar resize debouncer.
@@ -1626,7 +1822,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // through that size when using the shrink-to-nothing gesture.
     function hideSidebar() {
         if (isSrcPage) {
+            // @ts-expect-error
             window.rustdocCloseSourceSidebar();
+            // @ts-expect-error
             updateLocalStorage("src-sidebar-width", null);
             // [RUSTDOCIMPL] CSS variable fast path
             //
@@ -1639,14 +1837,19 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             //
             // So, to clear it, we need to clear all three.
             document.documentElement.style.removeProperty("--src-sidebar-width");
+            // @ts-expect-error
             sidebar.style.removeProperty("--src-sidebar-width");
+            // @ts-expect-error
             resizer.style.removeProperty("--src-sidebar-width");
         } else {
             addClass(document.documentElement, "hide-sidebar");
             updateLocalStorage("hide-sidebar", "true");
+            // @ts-expect-error
             updateLocalStorage("desktop-sidebar-width", null);
             document.documentElement.style.removeProperty("--desktop-sidebar-width");
+            // @ts-expect-error
             sidebar.style.removeProperty("--desktop-sidebar-width");
+            // @ts-expect-error
             resizer.style.removeProperty("--desktop-sidebar-width");
         }
     }
@@ -1659,6 +1862,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // remains visible all the time on there.
     function showSidebar() {
         if (isSrcPage) {
+            // @ts-expect-error
             window.rustdocShowSourceSidebar();
         } else {
             removeClass(document.documentElement, "hide-sidebar");
@@ -1674,6 +1878,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
      */
     function changeSidebarSize(size) {
         if (isSrcPage) {
+            // @ts-expect-error
             updateLocalStorage("src-sidebar-width", size);
             // [RUSTDOCIMPL] CSS variable fast path
             //
@@ -1681,11 +1886,16 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             // because the sidebar isn't actually loaded yet,
             // we scope this update to the sidebar to avoid hitting a slow
             // path in WebKit.
+            // @ts-expect-error
             sidebar.style.setProperty("--src-sidebar-width", size + "px");
+            // @ts-expect-error
             resizer.style.setProperty("--src-sidebar-width", size + "px");
         } else {
+            // @ts-expect-error
             updateLocalStorage("desktop-sidebar-width", size);
+            // @ts-expect-error
             sidebar.style.setProperty("--desktop-sidebar-width", size + "px");
+            // @ts-expect-error
             resizer.style.setProperty("--desktop-sidebar-width", size + "px");
         }
     }
@@ -1701,7 +1911,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // Respond to the resize handle event.
     // This function enforces size constraints, and implements the
     // shrink-to-nothing gesture based on thresholds defined above.
+    // @ts-expect-error
     function resize(e) {
+        // @ts-expect-error
         if (currentPointerId === null || currentPointerId !== e.pointerId) {
             return;
         }
@@ -1719,15 +1931,19 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             changeSidebarSize(constrainedPos);
             desiredSidebarSize = constrainedPos;
             if (pendingSidebarResizingFrame !== false) {
+                // @ts-expect-error
                 clearTimeout(pendingSidebarResizingFrame);
             }
+            // @ts-expect-error
             pendingSidebarResizingFrame = setTimeout(() => {
+                // @ts-expect-error
                 if (currentPointerId === null || pendingSidebarResizingFrame === false) {
                     return;
                 }
                 pendingSidebarResizingFrame = false;
                 document.documentElement.style.setProperty(
                     "--resizing-sidebar-width",
+                    // @ts-expect-error
                     desiredSidebarSize + "px",
                 );
             }, 100);
@@ -1739,51 +1955,69 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             return;
         }
         stopResize();
+        // @ts-expect-error
         if (desiredSidebarSize >= (window.innerWidth - BODY_MIN)) {
             changeSidebarSize(window.innerWidth - BODY_MIN);
+        // @ts-expect-error
         } else if (desiredSidebarSize !== null && desiredSidebarSize > SIDEBAR_MIN) {
+            // @ts-expect-error
             changeSidebarSize(desiredSidebarSize);
         }
     });
+    // @ts-expect-error
     function stopResize(e) {
+        // @ts-expect-error
         if (currentPointerId === null) {
             return;
         }
         if (e) {
             e.preventDefault();
         }
+        // @ts-expect-error
         desiredSidebarSize = sidebar.getBoundingClientRect().width;
+        // @ts-expect-error
         removeClass(resizer, "active");
         window.removeEventListener("pointermove", resize, false);
         window.removeEventListener("pointerup", stopResize, false);
         removeClass(document.documentElement, "sidebar-resizing");
         document.documentElement.style.removeProperty( "--resizing-sidebar-width");
+        // @ts-expect-error
         if (resizer.releasePointerCapture) {
+            // @ts-expect-error
             resizer.releasePointerCapture(currentPointerId);
             currentPointerId = null;
         }
     }
+    // @ts-expect-error
     function initResize(e) {
+        // @ts-expect-error
         if (currentPointerId !== null || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
             return;
         }
+        // @ts-expect-error
         if (resizer.setPointerCapture) {
+            // @ts-expect-error
             resizer.setPointerCapture(e.pointerId);
+            // @ts-expect-error
             if (!resizer.hasPointerCapture(e.pointerId)) {
                 // unable to capture pointer; something else has it
                 // on iOS, this usually means you long-clicked a link instead
+                // @ts-expect-error
                 resizer.releasePointerCapture(e.pointerId);
                 return;
             }
             currentPointerId = e.pointerId;
         }
+        // @ts-expect-error
         window.hideAllModals(false);
         e.preventDefault();
         window.addEventListener("pointermove", resize, false);
         window.addEventListener("pointercancel", stopResize, false);
         window.addEventListener("pointerup", stopResize, false);
+        // @ts-expect-error
         addClass(resizer, "active");
         addClass(document.documentElement, "sidebar-resizing");
+        // @ts-expect-error
         const pos = e.clientX - sidebar.offsetLeft - 3;
         document.documentElement.style.setProperty( "--resizing-sidebar-width", pos + "px");
         desiredSidebarSize = null;
@@ -1795,6 +2029,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
 // and the copy buttons on the code examples.
 (function() {
     // Common functions to copy buttons.
+    // @ts-expect-error
     function copyContentToClipboard(content) {
         const el = document.createElement("textarea");
         el.value = content;
@@ -1809,6 +2044,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         document.body.removeChild(el);
     }
 
+    // @ts-expect-error
     function copyButtonAnimation(button) {
         button.classList.add("clicked");
 
@@ -1831,6 +2067,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         // Most page titles are '<Item> in <path::to::module> - Rust', except
         // modules (which don't have the first part) and keywords/primitives
         // (which don't have a module path)
+        // @ts-expect-error
         const title = document.querySelector("title").textContent.replace(" - Rust", "");
         const [item, module] = title.split(" in ");
         const path = [item];
@@ -1843,6 +2080,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     };
 
     // Copy buttons on code examples.
+    // @ts-expect-error
     function copyCode(codeElem) {
         if (!codeElem) {
             // Should never happen, but the world is a dark and dangerous place.
@@ -1851,6 +2089,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         copyContentToClipboard(codeElem.textContent);
     }
 
+    // @ts-expect-error
     function getExampleWrap(event) {
         let elem = event.target;
         while (!hasClass(elem, "example-wrap")) {
@@ -1866,6 +2105,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         return elem;
     }
 
+    // @ts-expect-error
     function addCopyButton(event) {
         const elem = getExampleWrap(event);
         if (elem === null) {
@@ -1896,9 +2136,11 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             return;
         }
         const scrapedWrapped = elem.parentElement;
+        // @ts-expect-error
         window.updateScrapedExample(scrapedWrapped, parent);
     }
 
+    // @ts-expect-error
     function showHideCodeExampleButtons(event) {
         const elem = getExampleWrap(event);
         if (elem === null) {
@@ -1917,6 +2159,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         buttons.classList.toggle("keep-visible");
     }
 
+    // @ts-expect-error
     onEachLazy(document.querySelectorAll(".docblock .example-wrap"), elem => {
         elem.addEventListener("mouseover", addCopyButton);
         elem.addEventListener("click", showHideCodeExampleButtons);
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
new file mode 100644
index 00000000000..18a3e22113b
--- /dev/null
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -0,0 +1,387 @@
+// This file contains type definitions that are processed by the TypeScript Compiler but are
+// not put into the JavaScript we include as part of the documentation. It is used for
+// type checking. See README.md in this directory for more info.
+
+/* eslint-disable */
+declare global {
+    interface Window {
+        /** Make the current theme easy to find */
+        currentTheme: HTMLLinkElement|null;
+        /** Used by the popover tooltip code. */
+        RUSTDOC_TOOLTIP_HOVER_MS: number;
+        /** Used by the popover tooltip code. */
+        RUSTDOC_TOOLTIP_HOVER_EXIT_MS: number;
+        /** Search engine data used by main.js and search.js */
+        searchState: rustdoc.SearchState;
+        /** Global option, with a long list of "../"'s */
+        rootPath: string|null;
+        /**
+         * Currently opened crate.
+         * As a multi-page application, we know this never changes once set.
+         */
+        currentCrate: string|null;
+    }
+    interface HTMLElement {
+        /** Used by the popover tooltip code. */
+        TOOLTIP_FORCE_VISIBLE: boolean|undefined,
+        /** Used by the popover tooltip code */
+        TOOLTIP_HOVER_TIMEOUT: Timeout|undefined,
+    }
+}
+
+export = rustdoc;
+
+declare namespace rustdoc {
+    interface SearchState {
+        rustdocToolbar: HTMLElement|null;
+        loadingText: string;
+        input: HTMLInputElement|null;
+        title: string;
+        titleBeforeSearch: string;
+        timeout: number|null;
+        currentTab: number;
+        focusedByTab: [number|null, number|null, number|null];
+        clearInputTimeout: function;
+        outputElement: function(): HTMLElement|null;
+        focus: function();
+        defocus: function();
+        showResults: function(HTMLElement|null|undefined);
+        removeQueryParameters: function();
+        hideResults: function();
+        getQueryStringParams: function(): Object.<any, string>;
+        origPlaceholder: string;
+        setup: function();
+        setLoadingSearch: function();
+        descShards: Map<string, SearchDescShard[]>;
+        loadDesc: function({descShard: SearchDescShard, descIndex: number}): Promise<string|null>;
+        loadedDescShard: function(string, number, string);
+        isDisplayed: function(): boolean,
+    }
+
+    interface SearchDescShard {
+        crate: string;
+        promise: Promise<string[]>|null;
+        resolve: function(string[])|null;
+        shard: number;
+    }
+
+    /**
+     * A single parsed "atom" in a search query. For example,
+     * 
+     *     std::fmt::Formatter, Write -> Result<()>
+     *     ┏━━━━━━━━━━━━━━━━━━  ┌────    ┏━━━━━┅┅┅┅┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
+     *     ┃                    │        ┗ QueryElement {        ┊
+     *     ┃                    │              name: Result      ┊
+     *     ┃                    │              generics: [       ┊
+     *     ┃                    │                   QueryElement ┘
+     *     ┃                    │                   name: ()
+     *     ┃                    │              ]
+     *     ┃                    │          }
+     *     ┃                    └ QueryElement {
+     *     ┃                          name: Write
+     *     ┃                      }
+     *     ┗ QueryElement {
+     *           name: Formatter
+     *           pathWithoutLast: std::fmt
+     *       }
+     */
+    interface QueryElement {
+        name: string,
+        id: number|null,
+        fullPath: Array<string>,
+        pathWithoutLast: Array<string>,
+        pathLast: string,
+        normalizedPathLast: string,
+        generics: Array<QueryElement>,
+        bindings: Map<number, Array<QueryElement>>,
+        typeFilter: number|null,
+    }
+
+    /**
+     * Same as QueryElement, but bindings and typeFilter support strings
+     */
+    interface ParserQueryElement {
+        name: string,
+        id: number|null,
+        fullPath: Array<string>,
+        pathWithoutLast: Array<string>,
+        pathLast: string,
+        normalizedPathLast: string,
+        generics: Array<ParserQueryElement>,
+        bindings: Map<string, Array<ParserQueryElement>>,
+        bindingName: {name: string, generics: ParserQueryElement[]}|null,
+        typeFilter: string|null,
+    }
+
+    /**
+     * Intermediate parser state. Discarded when parsing is done.
+     */
+    interface ParserState {
+        pos: number;
+        length: number;
+        totalElems: number;
+        genericsElems: number;
+        typeFilter: (null|string);
+        userQuery: string;
+        isInBinding: (null|{name: string, generics: ParserQueryElement[]});
+    }
+
+    /**
+     * A complete parsed query.
+     */
+    interface ParsedQuery<T> {
+        userQuery: string,
+        elems: Array<T>,
+        returned: Array<T>,
+        foundElems: number,
+        totalElems: number,
+        literalSearch: boolean,
+        hasReturnArrow: boolean,
+        correction: string|null,
+        proposeCorrectionFrom: string|null,
+        proposeCorrectionTo: string|null,
+        typeFingerprint: Uint32Array,
+        error: Array<string> | null,
+    }
+
+    /**
+     * An entry in the search index database.
+     */
+    interface Row {
+        crate: string,
+        descShard: SearchDescShard,
+        id: number,
+        name: string,
+        normalizedName: string,
+        word: string,
+        parent: ({ty: number, name: string, path: string, exactPath: string}|null|undefined),
+        path: string,
+        ty: number,
+        type?: FunctionSearchType
+    }
+
+    /**
+     * The viewmodel for the search engine results page.
+     */
+    interface ResultsTable {
+        in_args: Array<ResultObject>,
+        returned: Array<ResultObject>,
+        others: Array<ResultObject>,
+        query: ParsedQuery,
+    }
+
+    type Results = Map<String, ResultObject>;
+
+    /**
+     * An annotated `Row`, used in the viewmodel.
+     */
+    interface ResultObject {
+        desc: string,
+        displayPath: string,
+        fullPath: string,
+        href: string,
+        id: number,
+        dist: number,
+        path_dist: number,
+        name: string,
+        normalizedName: string,
+        word: string,
+        index: number,
+        parent: (Object|undefined),
+        path: string,
+        ty: number,
+        type?: FunctionSearchType,
+        paramNames?: string[],
+        displayType: Promise<Array<Array<string>>>|null,
+        displayTypeMappedNames: Promise<Array<[string, Array<string>]>>|null,
+        item: Row,
+        dontValidate?: boolean,
+    }
+
+    /**
+     * A pair of [inputs, outputs], or 0 for null. This is stored in the search index.
+     * The JavaScript deserializes this into FunctionSearchType.
+     *
+     * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
+     * because `null` is four bytes while `0` is one byte.
+     *
+     * An input or output can be encoded as just a number if there is only one of them, AND
+     * it has no generics. The no generics rule exists to avoid ambiguity: imagine if you had
+     * a function with a single output, and that output had a single generic:
+     *
+     *     fn something() -> Result<usize, usize>
+     *
+     * If output was allowed to be any RawFunctionType, it would look like thi
+     *
+     *     [[], [50, [3, 3]]]
+     *
+     * The problem is that the above output could be interpreted as either a type with ID 50 and two
+     * generics, or it could be interpreted as a pair of types, the first one with ID 50 and the second
+     * with ID 3 and a single generic parameter that is also ID 3. We avoid this ambiguity by choosing
+     * in favor of the pair of types interpretation. This is why the `(number|Array<RawFunctionType>)`
+     * is used instead of `(RawFunctionType|Array<RawFunctionType>)`.
+     *
+     * The output can be skipped if it's actually unit and there's no type constraints. If thi
+     * function accepts constrained generics, then the output will be unconditionally emitted, and
+     * after it will come a list of trait constraints. The position of the item in the list will
+     * determine which type parameter it is. For example:
+     *
+     *     [1, 2, 3, 4, 5]
+     *      ^  ^  ^  ^  ^
+     *      |  |  |  |  - generic parameter (-3) of trait 5
+     *      |  |  |  - generic parameter (-2) of trait 4
+     *      |  |  - generic parameter (-1) of trait 3
+     *      |  - this function returns a single value (type 2)
+     *      - this function takes a single input parameter (type 1)
+     *
+     * Or, for a less contrived version:
+     *
+     *     [[[4, -1], 3], [[5, -1]], 11]
+     *      -^^^^^^^----   ^^^^^^^   ^^
+     *       |        |    |          - generic parameter, roughly `where -1: 11`
+     *       |        |    |            since -1 is the type parameter and 11 the trait
+     *       |        |    - function output 5<-1>
+     *       |        - the overall function signature is something like
+     *       |          `fn(4<-1>, 3) -> 5<-1> where -1: 11`
+     *       - function input, corresponds roughly to 4<-1>
+     *         4 is an index into the `p` array for a type
+     *         -1 is the generic parameter, given by 11
+     *
+     * If a generic parameter has multiple trait constraints, it gets wrapped in an array, just like
+     * function inputs and outputs:
+     *
+     *     [-1, -1, [4, 3]]
+     *              ^^^^^^ where -1: 4 + 3
+     *
+     * If a generic parameter's trait constraint has generic parameters, it gets wrapped in the array
+     * even if only one exists. In other words, the ambiguity of `4<3>` and `4 + 3` is resolved in
+     * favor of `4 + 3`:
+     *
+     *     [-1, -1, [[4, 3]]]
+     *              ^^^^^^^^ where -1: 4 + 3
+     *
+     *     [-1, -1, [5, [4, 3]]]
+     *              ^^^^^^^^^^^ where -1: 5, -2: 4 + 3
+     *
+     * If a generic parameter has no trait constraints (like in Rust, the `Sized` constraint i
+     * implied and a fake `?Sized` constraint used to note its absence), it will be filled in with 0.
+     */
+    type RawFunctionSearchType =
+        0 |
+        [(number|Array<RawFunctionType>)] |
+        [(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)] |
+        Array<(number|Array<RawFunctionType>)>
+    ;
+
+    /**
+     * A single function input or output type. This is either a single path ID, or a pair of
+     * [path ID, generics].
+     *
+     * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
+     * because `null` is four bytes while `0` is one byte.
+     */
+    type RawFunctionType = number | [number, Array<RawFunctionType>];
+
+    /**
+     * The type signature entry in the decoded search index.
+     * (The "Raw" objects are encoded differently to save space in the JSON).
+     */
+    interface FunctionSearchType {
+        inputs: Array<FunctionType>,
+        output: Array<FunctionType>,
+        where_clause: Array<Array<FunctionType>>,
+    }
+
+    /**
+     * A decoded function type, made from real objects.
+     * `ty` will be negative for generics, positive for types, and 0 for placeholders.
+     */
+    interface FunctionType {
+        id: null|number,
+        ty: number|null,
+        name?: string,
+        path: string|null,
+        exactPath: string|null,
+        unboxFlag: boolean,
+        generics: Array<FunctionType>,
+        bindings: Map<number, Array<FunctionType>>,
+    };
+
+    interface HighlightedFunctionType extends FunctionType {
+        generics: HighlightedFunctionType[],
+        bindings: Map<number, HighlightedFunctionType[]>,
+        highlighted?: boolean;
+    }
+
+    interface FingerprintableType {
+        id: number|null;
+        generics: FingerprintableType[];
+        bindings: Map<number, FingerprintableType[]>;
+    };
+
+    /**
+     * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f`
+     * are arrays with the same length. `q`, `a`, and `c` use a sparse
+     * representation for compactness.
+     *
+     * `n[i]` contains the name of an item.
+     *
+     * `t[i]` contains the type of that item
+     * (as a string of characters that represent an offset in `itemTypes`).
+     *
+     * `d[i]` contains the description of that item.
+     *
+     * `q` contains the full paths of the items. For compactness, it is a set of
+     * (index, path) pairs used to create a map. If a given index `i` is
+     * not present, this indicates "same as the last index present".
+     *
+     * `i[i]` contains an item's parent, usually a module. For compactness,
+     * it is a set of indexes into the `p` array.
+     *
+     * `f` contains function signatures, or `0` if the item isn't a function.
+     * More information on how they're encoded can be found in rustc-dev-guide
+     *
+     * Functions are themselves encoded as arrays. The first item is a list of
+     * types representing the function's inputs, and the second list item is a list
+     * of types representing the function's output. Tuples are flattened.
+     * Types are also represented as arrays; the first item is an index into the `p`
+     * array, while the second is a list of types representing any generic parameters.
+     *
+     * b[i] contains an item's impl disambiguator. This is only present if an item
+     * is defined in an impl block and, the impl block's type has more than one associated
+     * item with the same name.
+     *
+     * `a` defines aliases with an Array of pairs: [name, offset], where `offset`
+     * points into the n/t/d/q/i/f arrays.
+     *
+     * `doc` contains the description of the crate.
+     *
+     * `p` is a list of path/type pairs. It is used for parents and function parameters.
+     * The first item is the type, the second is the name, the third is the visible path (if any) and
+     * the fourth is the canonical path used for deduplication (if any).
+     *
+     * `r` is the canonical path used for deduplication of re-exported items.
+     * It is not used for associated items like methods (that's the fourth element
+     * of `p`) but is used for modules items like free functions.
+     *
+     * `c` is an array of item indices that are deprecated.
+     */
+    type RawSearchIndexCrate = {
+    doc: string,
+    a: Object,
+    n: Array<string>,
+    t: string,
+    D: string,
+    e: string,
+    q: Array<[number, string]>,
+    i: string,
+    f: string,
+    p: Array<[number, string] | [number, string, number] | [number, string, number, number] | [number, string, number, number, string]>,
+    b: Array<[number, String]>,
+    c: string,
+    r: Array<[number, number]>,
+    P: Array<[number, string]>,
+    };
+
+    type VlqData = VlqData[] | number;
+}
diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
index 98c53b8656f..d08f15a5bfa 100644
--- a/src/librustdoc/html/static/js/scrape-examples.js
+++ b/src/librustdoc/html/static/js/scrape-examples.js
@@ -1,5 +1,8 @@
 /* global addClass, hasClass, removeClass, onEachLazy */
 
+// Eventually fix this.
+// @ts-nocheck
+
 "use strict";
 
 (function() {
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 660484c133c..1ad32721e06 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -10,11 +10,19 @@ if (!Array.prototype.toSpliced) {
     // Can't use arrow functions, because we want `this`
     Array.prototype.toSpliced = function() {
         const me = this.slice();
+        // @ts-expect-error
         Array.prototype.splice.apply(me, arguments);
         return me;
     };
 }
 
+/**
+ *
+ * @template T
+ * @param {Iterable<T>} arr
+ * @param {function(T): any} func
+ * @param {function(T): boolean} funcBtwn
+ */
 function onEachBtwn(arr, func, funcBtwn) {
     let skipped = true;
     for (const value of arr) {
@@ -98,9 +106,24 @@ const NO_TYPE_FILTER = -1;
  * documentation.
  */
 const editDistanceState = {
+    /**
+     * @type {number[]}
+     */
     current: [],
+    /**
+     * @type {number[]}
+     */
     prev: [],
+    /**
+     * @type {number[]}
+     */
     prevPrev: [],
+    /**
+     * @param {string} a
+     * @param {string} b
+     * @param {number} limit
+     * @returns
+     */
     calculate: function calculate(a, b, limit) {
         // Ensure that `b` is the shorter string, minimizing memory use.
         if (a.length < b.length) {
@@ -186,14 +209,28 @@ const editDistanceState = {
     },
 };
 
+/**
+ * @param {string} a
+ * @param {string} b
+ * @param {number} limit
+ * @returns
+ */
 function editDistance(a, b, limit) {
     return editDistanceState.calculate(a, b, limit);
 }
 
+/**
+ * @param {string} c
+ * @returns {boolean}
+ */
 function isEndCharacter(c) {
     return "=,>-])".indexOf(c) !== -1;
 }
 
+/**
+ * @param {number} ty
+ * @returns
+ */
 function isFnLikeTy(ty) {
     return ty === TY_FN || ty === TY_METHOD || ty === TY_TYMETHOD;
 }
@@ -212,7 +249,7 @@ function isSeparatorCharacter(c) {
 /**
  * Returns `true` if the current parser position is starting with "->".
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  *
  * @return {boolean}
  */
@@ -223,7 +260,7 @@ function isReturnArrow(parserState) {
 /**
  * Increase current parser position until it doesn't find a whitespace anymore.
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  */
 function skipWhitespace(parserState) {
     while (parserState.pos < parserState.userQuery.length) {
@@ -238,7 +275,7 @@ function skipWhitespace(parserState) {
 /**
  * Returns `true` if the previous character is `lookingFor`.
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  * @param {String} lookingFor
  *
  * @return {boolean}
@@ -260,8 +297,8 @@ function prevIs(parserState, lookingFor) {
 /**
  * Returns `true` if the last element in the `elems` argument has generics.
  *
- * @param {Array<QueryElement>} elems
- * @param {ParserState} parserState
+ * @param {Array<rustdoc.ParserQueryElement>} elems
+ * @param {rustdoc.ParserState} parserState
  *
  * @return {boolean}
  */
@@ -270,6 +307,13 @@ function isLastElemGeneric(elems, parserState) {
         prevIs(parserState, ">");
 }
 
+/**
+ *
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
+ * @param {rustdoc.ParserQueryElement[]} elems
+ * @param {boolean} isInGenerics
+ */
 function getFilteredNextElem(query, parserState, elems, isInGenerics) {
     const start = parserState.pos;
     if (parserState.userQuery[parserState.pos] === ":" && !isPathStart(parserState)) {
@@ -294,6 +338,8 @@ function getFilteredNextElem(query, parserState, elems, isInGenerics) {
         // The type filter doesn't count as an element since it's a modifier.
         const typeFilterElem = elems.pop();
         checkExtraTypeFilterCharacters(start, parserState);
+        // typeFilterElem is not null. If it was, the elems.length check would have fired.
+        // @ts-expect-error
         parserState.typeFilter = typeFilterElem.normalizedPathLast;
         parserState.pos += 1;
         parserState.totalElems -= 1;
@@ -309,12 +355,13 @@ function getFilteredNextElem(query, parserState, elems, isInGenerics) {
  * If there is no `endChar`, this function will implicitly stop at the end
  * without raising an error.
  *
- * @param {ParsedQuery} query
- * @param {ParserState} parserState
- * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
- * @param {string} endChar            - This function will stop when it'll encounter this
- *                                      character.
- * @returns {{foundSeparator: bool}}
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
+ * @param {Array<rustdoc.ParserQueryElement>} elems
+ *     - This is where the new {QueryElement} will be added.
+ * @param {string} endChar - This function will stop when it'll encounter this
+ *                           character.
+ * @returns {{foundSeparator: boolean}}
  */
 function getItemsBefore(query, parserState, elems, endChar) {
     let foundStopChar = true;
@@ -385,6 +432,7 @@ function getItemsBefore(query, parserState, elems, endChar) {
             throw ["Unexpected ", c, " after ", extra];
         }
         if (!foundStopChar) {
+            /** @type {string[]} */
             let extra = [];
             if (isLastElemGeneric(query.elems, parserState)) {
                 extra = [" after ", ">"];
@@ -463,12 +511,14 @@ function getItemsBefore(query, parserState, elems, endChar) {
 }
 
 /**
- * @param {ParsedQuery} query
- * @param {ParserState} parserState
- * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
+ * @param {Array<rustdoc.ParserQueryElement>} elems
+ *     - This is where the new {QueryElement} will be added.
  * @param {boolean} isInGenerics
  */
 function getNextElem(query, parserState, elems, isInGenerics) {
+    /** @type {rustdoc.ParserQueryElement[]} */
     const generics = [];
 
     skipWhitespace(parserState);
@@ -588,6 +638,7 @@ function getNextElem(query, parserState, elems, isInGenerics) {
                 getFilteredNextElem(query, parserState, generics, isInGenerics);
                 generics[generics.length - 1].bindingName = makePrimitiveElement("output");
             } else {
+                // @ts-expect-error
                 generics.push(makePrimitiveElement(null, {
                     bindingName: makePrimitiveElement("output"),
                     typeFilter: null,
@@ -640,7 +691,8 @@ function getNextElem(query, parserState, elems, isInGenerics) {
  * Checks that the type filter doesn't have unwanted characters like `<>` (which are ignored
  * if empty).
  *
- * @param {ParserState} parserState
+ * @param {number} start
+ * @param {rustdoc.ParserState} parserState
  */
 function checkExtraTypeFilterCharacters(start, parserState) {
     const query = parserState.userQuery.slice(start, parserState.pos).trim();
@@ -658,12 +710,13 @@ function checkExtraTypeFilterCharacters(start, parserState) {
 }
 
 /**
- * @param {ParsedQuery} query
- * @param {ParserState} parserState
- * @param {string} name                  - Name of the query element.
- * @param {Array<QueryElement>} generics - List of generics of this query element.
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
+ * @param {string} name - Name of the query element.
+ * @param {Array<rustdoc.ParserQueryElement>} generics - List of generics of this query element.
+ * @param {boolean} isInGenerics
  *
- * @return {QueryElement}                - The newly created `QueryElement`.
+ * @return {rustdoc.ParserQueryElement} - The newly created `QueryElement`.
  */
 function createQueryElement(query, parserState, name, generics, isInGenerics) {
     const path = name.trim();
@@ -756,9 +809,15 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
     };
 }
 
+/**
+ *
+ * @param {string} name
+ * @param {Object=} extra
+ * @returns {rustdoc.ParserQueryElement}
+ */
 function makePrimitiveElement(name, extra) {
     return Object.assign({
-        name,
+        name: name,
         id: null,
         fullPath: [name],
         pathWithoutLast: [],
@@ -781,8 +840,8 @@ function makePrimitiveElement(name, extra) {
  * * There is more than one element.
  * * There is no closing `"`.
  *
- * @param {ParsedQuery} query
- * @param {ParserState} parserState
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
  * @param {boolean} isInGenerics
  */
 function getStringElem(query, parserState, isInGenerics) {
@@ -813,9 +872,9 @@ function getStringElem(query, parserState, isInGenerics) {
  * character or the end of the query. It returns the position of the last
  * character of the ident.
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  *
- * @return {integer}
+ * @return {number}
  */
 function getIdentEndPosition(parserState) {
     let afterIdent = consumeIdent(parserState);
@@ -890,6 +949,10 @@ function getIdentEndPosition(parserState) {
     return end;
 }
 
+/**
+ * @param {string} c
+ * @returns
+ */
 function isSpecialStartCharacter(c) {
     return "<\"".indexOf(c) !== -1;
 }
@@ -897,7 +960,7 @@ function isSpecialStartCharacter(c) {
 /**
  * Returns `true` if the current parser position is starting with "::".
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  *
  * @return {boolean}
  */
@@ -909,7 +972,7 @@ function isPathStart(parserState) {
  * If the current parser position is at the beginning of an identifier,
  * move the position to the end of it and return `true`. Otherwise, return `false`.
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  *
  * @return {boolean}
  */
@@ -935,14 +998,25 @@ function isPathSeparator(c) {
     return c === ":" || c === " ";
 }
 
+/**
+ * @template T
+ */
 class VlqHexDecoder {
+    /**
+     * @param {string} string
+     * @param {function(rustdoc.VlqData): T} cons
+     */
     constructor(string, cons) {
         this.string = string;
         this.cons = cons;
         this.offset = 0;
+        /** @type {T[]} */
         this.backrefQueue = [];
     }
-    // call after consuming `{`
+    /**
+     * call after consuming `{`
+     * @returns {rustdoc.VlqData[]}
+     */
     decodeList() {
         let c = this.string.charCodeAt(this.offset);
         const ret = [];
@@ -953,7 +1027,10 @@ class VlqHexDecoder {
         this.offset += 1; // eat cb
         return ret;
     }
-    // consumes and returns a list or integer
+    /**
+     * consumes and returns a list or integer
+     * @returns {rustdoc.VlqData}
+     */
     decode() {
         let n = 0;
         let c = this.string.charCodeAt(this.offset);
@@ -972,6 +1049,9 @@ class VlqHexDecoder {
         this.offset += 1;
         return sign ? -value : value;
     }
+    /**
+     * @returns {T}
+     */
     next() {
         const c = this.string.charCodeAt(this.offset);
         // sixteen characters after "0" are backref
@@ -994,6 +1074,7 @@ class VlqHexDecoder {
     }
 }
 class RoaringBitmap {
+    /** @param {string} str */
     constructor(str) {
         // https://github.com/RoaringBitmap/RoaringFormatSpec
         //
@@ -1063,6 +1144,7 @@ class RoaringBitmap {
             }
         }
     }
+    /** @param {number} keyvalue */
     contains(keyvalue) {
         const key = keyvalue >> 16;
         const value = keyvalue & 0xFFFF;
@@ -1091,10 +1173,15 @@ class RoaringBitmap {
 }
 
 class RoaringBitmapRun {
+    /**
+     * @param {number} runcount
+     * @param {Uint8Array} array
+     */
     constructor(runcount, array) {
         this.runcount = runcount;
         this.array = array;
     }
+    /** @param {number} value */
     contains(value) {
         // Binary search algorithm copied from
         // https://en.wikipedia.org/wiki/Binary_search#Procedure
@@ -1120,10 +1207,15 @@ class RoaringBitmapRun {
     }
 }
 class RoaringBitmapArray {
+    /**
+     * @param {number} cardinality
+     * @param {Uint8Array} array
+     */
     constructor(cardinality, array) {
         this.cardinality = cardinality;
         this.array = array;
     }
+    /** @param {number} value */
     contains(value) {
         // Binary search algorithm copied from
         // https://en.wikipedia.org/wiki/Binary_search#Procedure
@@ -1148,9 +1240,13 @@ class RoaringBitmapArray {
     }
 }
 class RoaringBitmapBits {
+    /**
+     * @param {Uint8Array} array
+     */
     constructor(array) {
         this.array = array;
     }
+    /** @param {number} value */
     contains(value) {
         return !!(this.array[value >> 3] & (1 << (value & 7)));
     }
@@ -1176,9 +1272,9 @@ class RoaringBitmapBits {
  * matches
  * : A list of search index IDs for this node.
  *
- * @typedef {{
- *     children: [NameTrie],
- *     matches: [number],
+ * @type {{
+ *     children: NameTrie[],
+ *     matches: number[],
  * }}
  */
 class NameTrie {
@@ -1186,9 +1282,20 @@ class NameTrie {
         this.children = [];
         this.matches = [];
     }
+    /**
+     * @param {string} name
+     * @param {number} id
+     * @param {Map<string, NameTrie[]>} tailTable
+     */
     insert(name, id, tailTable) {
         this.insertSubstring(name, 0, id, tailTable);
     }
+    /**
+     * @param {string} name
+     * @param {number} substart
+     * @param {number} id
+     * @param {Map<string, NameTrie[]>} tailTable
+     */
     insertSubstring(name, substart, id, tailTable) {
         const l = name.length;
         if (substart === l) {
@@ -1201,10 +1308,13 @@ class NameTrie {
             } else {
                 child = new NameTrie();
                 this.children[sb] = child;
+                /** @type {NameTrie[]} */
                 let sste;
                 if (substart >= 2) {
                     const tail = name.substring(substart - 2, substart + 1);
                     if (tailTable.has(tail)) {
+                        // it's not undefined
+                        // @ts-expect-error
                         sste = tailTable.get(tail);
                     } else {
                         sste = [];
@@ -1216,6 +1326,10 @@ class NameTrie {
             child.insertSubstring(name, substart + 1, id, tailTable);
         }
     }
+    /**
+     * @param {string} name
+     * @param {Map<string, NameTrie[]>} tailTable
+     */
     search(name, tailTable) {
         const results = new Set();
         this.searchSubstringPrefix(name, 0, results);
@@ -1226,6 +1340,8 @@ class NameTrie {
             this.searchLev(name, 0, levParams, results);
             const tail = name.substring(0, 3);
             if (tailTable.has(tail)) {
+                // it's not undefined
+                // @ts-expect-error
                 for (const entry of tailTable.get(tail)) {
                     entry.searchSubstringPrefix(name, 3, results);
                 }
@@ -1233,6 +1349,11 @@ class NameTrie {
         }
         return [...results];
     }
+    /**
+     * @param {string} name
+     * @param {number} substart
+     * @param {Set<number>} results
+     */
     searchSubstringPrefix(name, substart, results) {
         const l = name.length;
         if (substart === l) {
@@ -1240,14 +1361,18 @@ class NameTrie {
                 results.add(match);
             }
             // breadth-first traversal orders prefix matches by length
+            /** @type {NameTrie[]} */
             let unprocessedChildren = [];
             for (const child of this.children) {
                 if (child) {
                     unprocessedChildren.push(child);
                 }
             }
+            /** @type {NameTrie[]} */
             let nextSet = [];
             while (unprocessedChildren.length !== 0) {
+                /** @type {NameTrie} */
+                // @ts-expect-error
                 const next = unprocessedChildren.pop();
                 for (const child of next.children) {
                     if (child) {
@@ -1270,10 +1395,18 @@ class NameTrie {
             }
         }
     }
+    /**
+     * @param {string} name
+     * @param {number} substart
+     * @param {Lev2TParametricDescription|Lev1TParametricDescription} levParams
+     * @param {Set<number>} results
+     */
     searchLev(name, substart, levParams, results) {
         const stack = [[this, 0]];
         const n = levParams.n;
         while (stack.length !== 0) {
+            // It's not empty
+            //@ts-expect-error
             const [trie, levState] = stack.pop();
             for (const [charCode, child] of trie.children.entries()) {
                 if (!child) {
@@ -1305,6 +1438,11 @@ class NameTrie {
 }
 
 class DocSearch {
+    /**
+     * @param {Map<string, rustdoc.RawSearchIndexCrate>} rawSearchIndex
+     * @param {string} rootPath
+     * @param {rustdoc.SearchState} searchState
+     */
     constructor(rawSearchIndex, rootPath, searchState) {
         /**
          * @type {Map<String, RoaringBitmap>}
@@ -1317,19 +1455,19 @@ class DocSearch {
         /**
          *  @type {Uint32Array}
          */
-        this.functionTypeFingerprint = null;
+        this.functionTypeFingerprint = new Uint32Array(0);
         /**
          * Map from normalized type names to integers. Used to make type search
          * more efficient.
          *
-         * @type {Map<string, {id: integer, assocOnly: boolean}>}
+         * @type {Map<string, {id: number, assocOnly: boolean}>}
          */
         this.typeNameIdMap = new Map();
         /**
          * Map from type ID to associated type name. Used for display,
          * not for search.
          *
-         * @type {Map<integer, string>}
+         * @type {Map<number, string>}
          */
         this.assocTypeIdNameMap = new Map();
         this.ALIASES = new Map();
@@ -1338,64 +1476,88 @@ class DocSearch {
 
         /**
          * Special type name IDs for searching by array.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfArray = this.buildTypeMapIndex("array");
         /**
          * Special type name IDs for searching by slice.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfSlice = this.buildTypeMapIndex("slice");
         /**
          * Special type name IDs for searching by both array and slice (`[]` syntax).
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfArrayOrSlice = this.buildTypeMapIndex("[]");
         /**
          * Special type name IDs for searching by tuple.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfTuple = this.buildTypeMapIndex("tuple");
         /**
          * Special type name IDs for searching by unit.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfUnit = this.buildTypeMapIndex("unit");
         /**
          * Special type name IDs for searching by both tuple and unit (`()` syntax).
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfTupleOrUnit = this.buildTypeMapIndex("()");
         /**
          * Special type name IDs for searching `fn`.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfFn = this.buildTypeMapIndex("fn");
         /**
          * Special type name IDs for searching `fnmut`.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfFnMut = this.buildTypeMapIndex("fnmut");
         /**
          * Special type name IDs for searching `fnonce`.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfFnOnce = this.buildTypeMapIndex("fnonce");
         /**
          * Special type name IDs for searching higher order functions (`->` syntax).
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfHof = this.buildTypeMapIndex("->");
         /**
          * Special type name IDs the output assoc type.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfOutput = this.buildTypeMapIndex("output", true);
         /**
          * Special type name IDs for searching by reference.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfReference = this.buildTypeMapIndex("reference");
 
         /**
          * Empty, immutable map used in item search types with no bindings.
          *
-         * @type {Map<number, Array<FunctionType>>}
+         * @type {Map<number, Array<any>>}
          */
         this.EMPTY_BINDINGS_MAP = new Map();
 
         /**
          * Empty, immutable map used in item search types with no bindings.
          *
-         * @type {Array<FunctionType>}
+         * @type {Array<any>}
          */
         this.EMPTY_GENERICS_ARRAY = [];
 
@@ -1403,7 +1565,7 @@ class DocSearch {
          * Object pool for function types with no bindings or generics.
          * This is reset after loading the index.
          *
-         * @type {Map<number|null, FunctionType>}
+         * @type {Map<number|null, rustdoc.FunctionType>}
          */
         this.TYPES_POOL = new Map();
 
@@ -1422,8 +1584,9 @@ class DocSearch {
         this.tailTable = new Map();
 
         /**
-         *  @type {Array<Row>}
+         *  @type {Array<rustdoc.Row>}
          */
+        // @ts-expect-error
         this.searchIndex = this.buildIndex(rawSearchIndex);
     }
 
@@ -1436,9 +1599,9 @@ class DocSearch {
      * get the same ID.
      *
      * @param {string} name
-     * @param {boolean} isAssocType - True if this is an assoc type
+     * @param {boolean=} isAssocType - True if this is an assoc type
      *
-     * @returns {integer}
+     * @returns {number?}
      */
     buildTypeMapIndex(name, isAssocType) {
         if (name === "" || name === null) {
@@ -1446,12 +1609,14 @@ class DocSearch {
         }
 
         if (this.typeNameIdMap.has(name)) {
+            /** @type {{id: number, assocOnly: boolean}} */
+            // @ts-expect-error
             const obj = this.typeNameIdMap.get(name);
-            obj.assocOnly = isAssocType && obj.assocOnly;
+            obj.assocOnly = !!(isAssocType && obj.assocOnly);
             return obj.id;
         } else {
             const id = this.typeNameIdMap.size;
-            this.typeNameIdMap.set(name, { id, assocOnly: isAssocType });
+            this.typeNameIdMap.set(name, { id, assocOnly: !!isAssocType });
             return id;
         }
     }
@@ -1469,13 +1634,26 @@ class DocSearch {
      * The format for individual function types is encoded in
      * librustdoc/html/render/mod.rs: impl Serialize for RenderType
      *
-     * @param {null|Array<RawFunctionType>} types
-     * @param {Array<{name: string, ty: number}>} lowercasePaths
+     * @param {null|Array<rustdoc.RawFunctionType>} types
+     * @param {Array<{
+     *     name: string,
+    *     ty: number,
+    *     path: string|null,
+    *     exactPath: string|null,
+    *     unboxFlag: boolean
+    * }>} paths
+    * @param {Array<{
+    *     name: string,
+    *     ty: number,
+    *     path: string|null,
+    *     exactPath: string|null,
+    *     unboxFlag: boolean,
+    * }>} lowercasePaths
      *
-     * @return {Array<FunctionSearchType>}
+     * @return {Array<rustdoc.FunctionType>}
      */
     buildItemSearchTypeAll(types, paths, lowercasePaths) {
-        return types.length > 0 ?
+        return types && types.length > 0 ?
             types.map(type => this.buildItemSearchType(type, paths, lowercasePaths)) :
             this.EMPTY_GENERICS_ARRAY;
     }
@@ -1483,7 +1661,22 @@ class DocSearch {
     /**
      * Converts a single type.
      *
-     * @param {RawFunctionType} type
+     * @param {rustdoc.RawFunctionType} type
+     * @param {Array<{
+     *     name: string,
+     *     ty: number,
+     *     path: string|null,
+     *     exactPath: string|null,
+     *     unboxFlag: boolean
+     * }>} paths
+     * @param {Array<{
+     *     name: string,
+     *     ty: number,
+     *     path: string|null,
+     *     exactPath: string|null,
+     *     unboxFlag: boolean,
+     * }>} lowercasePaths
+     * @param {boolean=} isAssocType
      */
     buildItemSearchType(type, paths, lowercasePaths, isAssocType) {
         const PATH_INDEX_DATA = 0;
@@ -1501,7 +1694,9 @@ class DocSearch {
                 paths,
                 lowercasePaths,
             );
+            // @ts-expect-error
             if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) {
+                // @ts-expect-error
                 bindings = new Map(type[BINDINGS_DATA].map(binding => {
                     const [assocType, constraints] = binding;
                     // Associated type constructors are represented sloppily in rustdoc's
@@ -1524,7 +1719,7 @@ class DocSearch {
             }
         }
         /**
-         * @type {FunctionType}
+         * @type {rustdoc.FunctionType}
          */
         let result;
         if (pathIndex < 0) {
@@ -1555,7 +1750,7 @@ class DocSearch {
         } else {
             const item = lowercasePaths[pathIndex - 1];
             const id = this.buildTypeMapIndex(item.name, isAssocType);
-            if (isAssocType) {
+            if (isAssocType && id !== null) {
                 this.assocTypeIdNameMap.set(id, paths[pathIndex - 1].name);
             }
             result = {
@@ -1585,6 +1780,7 @@ class DocSearch {
             if (cr.bindings.size === result.bindings.size && cr.bindings !== result.bindings) {
                 let ok = true;
                 for (const [k, v] of cr.bindings.entries()) {
+                    // @ts-expect-error
                     const v2 = result.bindings.get(v);
                     if (!v2) {
                         ok = false;
@@ -1629,7 +1825,7 @@ class DocSearch {
      * [^1]: Distance is the relatively naive metric of counting the number of distinct items in
      * the function that are not present in the query.
      *
-     * @param {FunctionType|QueryElement} type - a single type
+     * @param {rustdoc.FingerprintableType} type - a single type
      * @param {Uint32Array} output - write the fingerprint to this data structure: uses 128 bits
      */
     buildFunctionTypeFingerprint(type, output) {
@@ -1647,9 +1843,12 @@ class DocSearch {
             input === this.typeNameIdOfFnOnce) {
             input = this.typeNameIdOfHof;
         }
-        // http://burtleburtle.net/bob/hash/integer.html
-        // ~~ is toInt32. It's used before adding, so
-        // the number stays in safe integer range.
+        /**
+         * http://burtleburtle.net/bob/hash/integer.html
+         * ~~ is toInt32. It's used before adding, so
+         * the number stays in safe integer range.
+         * @param {number} k
+         */
         const hashint1 = k => {
             k = (~~k + 0x7ed55d16) + (k << 12);
             k = (k ^ 0xc761c23c) ^ (k >>> 19);
@@ -1658,6 +1857,7 @@ class DocSearch {
             k = (~~k + 0xfd7046c5) + (k << 3);
             return (k ^ 0xb55a4f09) ^ (k >>> 16);
         };
+        /** @param {number} k */
         const hashint2 = k => {
             k = ~k + (k << 15);
             k ^= k >>> 12;
@@ -1684,6 +1884,14 @@ class DocSearch {
         for (const g of type.generics) {
             this.buildFunctionTypeFingerprint(g, output);
         }
+        /**
+         * @type {{
+         *   id: number|null,
+         *   ty: number,
+         *   generics: rustdoc.FingerprintableType[],
+         *   bindings: Map<number, rustdoc.FingerprintableType[]>
+         * }}
+         */
         const fb = {
             id: null,
             ty: 0,
@@ -1700,7 +1908,7 @@ class DocSearch {
     /**
      * Convert raw search index into in-memory search index.
      *
-     * @param {[string, RawSearchIndexCrate][]} rawSearchIndex
+     * @param {Map<string, rustdoc.RawSearchIndexCrate>} rawSearchIndex
      */
     buildIndex(rawSearchIndex) {
         /**
@@ -1714,19 +1922,37 @@ class DocSearch {
          * The raw function search type format is generated using serde in
          * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string
          *
-         * @param {Array<{name: string, ty: number}>} paths
-         * @param {Array<{name: string, ty: number}>} lowercasePaths
+         * @param {Array<{
+         *     name: string,
+         *     ty: number,
+         *     path: string|null,
+         *     exactPath: string|null,
+         *     unboxFlag: boolean
+         * }>} paths
+         * @param {Array<{
+         *     name: string,
+         *     ty: number,
+         *     path: string|null,
+         *     exactPath: string|null,
+         *     unboxFlag: boolean
+         * }>} lowercasePaths
          *
-         * @return {null|FunctionSearchType}
+         * @return {function(rustdoc.RawFunctionSearchType): null|rustdoc.FunctionSearchType}
          */
         const buildFunctionSearchTypeCallback = (paths, lowercasePaths) => {
-            return functionSearchType => {
+            /**
+             * @param {rustdoc.RawFunctionSearchType} functionSearchType
+             */
+            const cb = functionSearchType => {
                 if (functionSearchType === 0) {
                     return null;
                 }
                 const INPUTS_DATA = 0;
                 const OUTPUT_DATA = 1;
-                let inputs, output;
+                /** @type {rustdoc.FunctionType[]} */
+                let inputs;
+                /** @type {rustdoc.FunctionType[]} */
+                let output;
                 if (typeof functionSearchType[INPUTS_DATA] === "number") {
                     inputs = [
                         this.buildItemSearchType(
@@ -1753,6 +1979,7 @@ class DocSearch {
                         ];
                     } else {
                         output = this.buildItemSearchTypeAll(
+                            // @ts-expect-error
                             functionSearchType[OUTPUT_DATA],
                             paths,
                             lowercasePaths,
@@ -1765,8 +1992,10 @@ class DocSearch {
                 const l = functionSearchType.length;
                 for (let i = 2; i < l; ++i) {
                     where_clause.push(typeof functionSearchType[i] === "number"
+                        // @ts-expect-error
                         ? [this.buildItemSearchType(functionSearchType[i], paths, lowercasePaths)]
                         : this.buildItemSearchTypeAll(
+                            // @ts-expect-error
                             functionSearchType[i],
                             paths,
                             lowercasePaths,
@@ -1776,6 +2005,7 @@ class DocSearch {
                     inputs, output, where_clause,
                 };
             };
+            return cb;
         };
 
         const searchIndex = [];
@@ -1798,7 +2028,12 @@ class DocSearch {
         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);
+            const itemDescShardDecoder = new VlqHexDecoder(crateCorpus.D, noop => {
+                /** @type {number} */
+                // @ts-expect-error
+                const n = noop;
+                return n;
+            });
             let descShard = {
                 crate,
                 shard: 0,
@@ -1817,7 +2052,7 @@ class DocSearch {
             /**
              * List of generic function type parameter names.
              * Used for display, not for searching.
-             * @type {[string]}
+             * @type {string[]}
              */
             let lastParamNames = [];
 
@@ -1847,6 +2082,8 @@ class DocSearch {
             id += 1;
             searchIndex.push(crateRow);
             currentIndex += 1;
+            // it's not undefined
+            // @ts-expect-error
             if (!this.searchIndexEmptyDesc.get(crate).contains(0)) {
                 descIndex += 1;
             }
@@ -1870,7 +2107,7 @@ class DocSearch {
             const implDisambiguator = new Map(crateCorpus.b);
             // an array of [(Number) item type,
             //              (String) name]
-            const paths = crateCorpus.p;
+            const rawPaths = crateCorpus.p;
             // an array of [(String) alias name
             //             [Number] index to items]
             const aliases = crateCorpus.a;
@@ -1879,33 +2116,61 @@ class DocSearch {
             // an item whose index is not present will fall back to the previous present path
             const itemParamNames = new Map(crateCorpus.P);
 
-            // an array of [{name: String, ty: Number}]
+            /**
+             * @type {Array<{
+             *     name: string,
+             *     ty: number,
+             *     path: string|null,
+             *     exactPath: string|null,
+             *     unboxFlag: boolean
+             * }>}
+             */
             const lowercasePaths = [];
+            /**
+             * @type {Array<{
+             *     name: string,
+             *     ty: number,
+             *     path: string|null,
+             *     exactPath: string|null,
+             *     unboxFlag: boolean
+             * }>}
+             */
+            const paths = [];
 
             // a string representing the list of function types
             const itemFunctionDecoder = new VlqHexDecoder(
                 crateCorpus.f,
+                // @ts-expect-error
                 buildFunctionSearchTypeCallback(paths, lowercasePaths),
             );
 
             // convert `rawPaths` entries into object form
             // generate normalizedPaths for function search mode
-            let len = paths.length;
+            let len = rawPaths.length;
             let lastPath = itemPaths.get(0);
             for (let i = 0; i < len; ++i) {
-                const elem = paths[i];
+                const elem = rawPaths[i];
                 const ty = elem[0];
                 const name = elem[1];
                 let path = null;
                 if (elem.length > 2 && elem[2] !== null) {
+                    // @ts-expect-error
                     path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath;
                     lastPath = path;
                 }
-                const exactPath = elem.length > 3 && elem[3] !== null ?
+                let exactPath = elem.length > 3 && elem[3] !== null ?
+                    // @ts-expect-error
                     itemPaths.get(elem[3]) :
                     path;
                 const unboxFlag = elem.length > 4 && !!elem[4];
 
+                if (path === undefined) {
+                    path = null;
+                }
+                if (exactPath === undefined) {
+                    exactPath = null;
+                }
+
                 lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath, unboxFlag });
                 paths[i] = { ty, name, path, exactPath, unboxFlag };
             }
@@ -1924,6 +2189,7 @@ class DocSearch {
             for (let i = 0; i < len; ++i) {
                 const bitIndex = i + 1;
                 if (descIndex >= descShard.len &&
+                    // @ts-expect-error
                     !this.searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
                     descShard = {
                         crate,
@@ -1938,8 +2204,11 @@ class DocSearch {
                 }
                 const name = itemNames[i] === "" ? lastName : itemNames[i];
                 const word = itemNames[i] === "" ? lastWord : itemNames[i].toLowerCase();
+                /** @type {string} */
+                // @ts-expect-error
                 const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
                 const paramNames = itemParamNames.has(i) ?
+                    // @ts-expect-error
                     itemParamNames.get(i).split(",") :
                     lastParamNames;
                 const type = itemFunctionDecoder.next();
@@ -1971,7 +2240,9 @@ class DocSearch {
                     descShard,
                     descIndex,
                     exactPath: itemReexports.has(i) ?
+                        // @ts-expect-error
                         itemPaths.get(itemReexports.get(i)) : path,
+                    // @ts-expect-error
                     parent: itemParentIdx > 0 ? paths[itemParentIdx - 1] : undefined,
                     type,
                     paramNames,
@@ -1987,6 +2258,7 @@ class DocSearch {
                 searchIndex.push(row);
                 lastPath = row.path;
                 lastParamNames = row.paramNames;
+                // @ts-expect-error
                 if (!this.searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
                     descIndex += 1;
                 }
@@ -2002,13 +2274,16 @@ class DocSearch {
                         continue;
                     }
 
+                    // @ts-expect-error
                     let currentNameAliases;
                     if (currentCrateAliases.has(alias_name)) {
                         currentNameAliases = currentCrateAliases.get(alias_name);
                     } else {
                         currentNameAliases = [];
+                        // @ts-expect-error
                         currentCrateAliases.set(alias_name, currentNameAliases);
                     }
+                    // @ts-expect-error
                     for (const local_alias of aliases[alias_name]) {
                         currentNameAliases.push(local_alias + currentIndex);
                     }
@@ -2030,11 +2305,15 @@ class DocSearch {
      *
      * When adding new things to the parser, add them there, too!
      *
-     * @param  {string} val     - The user query
+     * @param  {string} userQuery - The user query
      *
-     * @return {ParsedQuery}    - The parsed query
+     * @return {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} - The parsed query
      */
     static parseQuery(userQuery) {
+        /**
+         * @param {string} typename
+         * @returns {number}
+         */
         function itemTypeFromName(typename) {
             const index = itemTypes.findIndex(i => i === typename);
             if (index < 0) {
@@ -2043,14 +2322,19 @@ class DocSearch {
             return index;
         }
 
+        /**
+         * @param {rustdoc.ParserQueryElement} elem
+         */
         function convertTypeFilterOnElem(elem) {
             if (elem.typeFilter !== null) {
                 let typeFilter = elem.typeFilter;
                 if (typeFilter === "const") {
                     typeFilter = "constant";
                 }
+                // @ts-expect-error
                 elem.typeFilter = itemTypeFromName(typeFilter);
             } else {
+                // @ts-expect-error
                 elem.typeFilter = NO_TYPE_FILTER;
             }
             for (const elem2 of elem.generics) {
@@ -2068,7 +2352,7 @@ class DocSearch {
          *
          * @param {string} userQuery
          *
-         * @return {ParsedQuery}
+         * @return {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>}
          */
         function newParsedQuery(userQuery) {
             return {
@@ -2094,8 +2378,8 @@ class DocSearch {
         * Parses the provided `query` input to fill `parserState`. If it encounters an error while
         * parsing `query`, it'll throw an error.
         *
-        * @param {ParsedQuery} query
-        * @param {ParserState} parserState
+        * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+        * @param {rustdoc.ParserState} parserState
         */
         function parseInput(query, parserState) {
             let foundStopChar = true;
@@ -2125,6 +2409,7 @@ class DocSearch {
                 if (!foundStopChar) {
                     let extra = "";
                     if (isLastElemGeneric(query.elems, parserState)) {
+                        // @ts-expect-error
                         extra = [" after ", ">"];
                     } else if (prevIs(parserState, "\"")) {
                         throw ["Cannot have more than one element if you use quotes"];
@@ -2208,6 +2493,8 @@ class DocSearch {
             }
         } catch (err) {
             query = newParsedQuery(userQuery);
+            // is string list
+            // @ts-expect-error
             query.error = err;
             return query;
         }
@@ -2224,25 +2511,167 @@ class DocSearch {
     /**
      * Executes the parsed query and builds a {ResultsTable}.
      *
-     * @param  {ParsedQuery} parsedQuery - The parsed user query
-     * @param  {Object} [filterCrates]   - Crate to search in if defined
-     * @param  {Object} [currentCrate]   - Current crate, to rank results from this crate higher
+     * @param  {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} origParsedQuery
+     *     - The parsed user query
+     * @param  {Object} [filterCrates] - Crate to search in if defined
+     * @param  {Object} [currentCrate] - Current crate, to rank results from this crate higher
      *
-     * @return {ResultsTable}
+     * @return {Promise<rustdoc.ResultsTable>}
      */
-    async execQuery(parsedQuery, filterCrates, currentCrate) {
+    async execQuery(origParsedQuery, filterCrates, currentCrate) {
         const results_others = new Map(), results_in_args = new Map(),
             results_returned = new Map();
 
+        /** @type {rustdoc.ParsedQuery<rustdoc.QueryElement>} */
+        // @ts-expect-error
+        const parsedQuery = origParsedQuery;
+
+        const queryLen =
+            parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
+            parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
+        const maxEditDistance = Math.floor(queryLen / 3);
+
+        /**
+         * @type {Map<string, number>}
+         */
+        const genericSymbols = new Map();
+
+        /**
+         * Convert names to ids in parsed query elements.
+         * This is not used for the "In Names" tab, but is used for the
+         * "In Params", "In Returns", and "In Function Signature" tabs.
+         *
+         * If there is no matching item, but a close-enough match, this
+         * function also that correction.
+         *
+         * See `buildTypeMapIndex` for more information.
+         *
+         * @param {rustdoc.QueryElement} elem
+         * @param {boolean} isAssocType
+         */
+        const convertNameToId = (elem, isAssocType) => {
+            const loweredName = elem.pathLast.toLowerCase();
+            if (this.typeNameIdMap.has(loweredName) &&
+                // @ts-expect-error
+                (isAssocType || !this.typeNameIdMap.get(loweredName).assocOnly)) {
+                // @ts-expect-error
+                elem.id = this.typeNameIdMap.get(loweredName).id;
+            } else if (!parsedQuery.literalSearch) {
+                let match = null;
+                let matchDist = maxEditDistance + 1;
+                let matchName = "";
+                for (const [name, { id, assocOnly }] of this.typeNameIdMap) {
+                    const dist = Math.min(
+                        editDistance(name, loweredName, maxEditDistance),
+                        editDistance(name, elem.normalizedPathLast, maxEditDistance),
+                    );
+                    if (dist <= matchDist && dist <= maxEditDistance &&
+                        (isAssocType || !assocOnly)) {
+                        if (dist === matchDist && matchName > name) {
+                            continue;
+                        }
+                        match = id;
+                        matchDist = dist;
+                        matchName = name;
+                    }
+                }
+                if (match !== null) {
+                    parsedQuery.correction = matchName;
+                }
+                elem.id = match;
+            }
+            if ((elem.id === null && parsedQuery.totalElems > 1 && elem.typeFilter === -1
+                && elem.generics.length === 0 && elem.bindings.size === 0)
+                || elem.typeFilter === TY_GENERIC) {
+                if (genericSymbols.has(elem.normalizedPathLast)) {
+                    // @ts-expect-error
+                    elem.id = genericSymbols.get(elem.normalizedPathLast);
+                } else {
+                    elem.id = -(genericSymbols.size + 1);
+                    genericSymbols.set(elem.normalizedPathLast, elem.id);
+                }
+                if (elem.typeFilter === -1 && elem.normalizedPathLast.length >= 3) {
+                    // Silly heuristic to catch if the user probably meant
+                    // to not write a generic parameter. We don't use it,
+                    // just bring it up.
+                    const maxPartDistance = Math.floor(elem.normalizedPathLast.length / 3);
+                    let matchDist = maxPartDistance + 1;
+                    let matchName = "";
+                    for (const name of this.typeNameIdMap.keys()) {
+                        const dist = editDistance(
+                            name,
+                            elem.normalizedPathLast,
+                            maxPartDistance,
+                        );
+                        if (dist <= matchDist && dist <= maxPartDistance) {
+                            if (dist === matchDist && matchName > name) {
+                                continue;
+                            }
+                            matchDist = dist;
+                            matchName = name;
+                        }
+                    }
+                    if (matchName !== "") {
+                        parsedQuery.proposeCorrectionFrom = elem.name;
+                        parsedQuery.proposeCorrectionTo = matchName;
+                    }
+                }
+                elem.typeFilter = TY_GENERIC;
+            }
+            if (elem.generics.length > 0 && elem.typeFilter === TY_GENERIC) {
+                // Rust does not have HKT
+                parsedQuery.error = [
+                    "Generic type parameter ",
+                    elem.name,
+                    " does not accept generic parameters",
+                ];
+            }
+            for (const elem2 of elem.generics) {
+                // @ts-expect-error
+                convertNameToId(elem2);
+            }
+            elem.bindings = new Map(Array.from(elem.bindings.entries())
+                .map(entry => {
+                    const [name, constraints] = entry;
+                    // @ts-expect-error
+                    if (!this.typeNameIdMap.has(name)) {
+                        parsedQuery.error = [
+                            "Type parameter ",
+                            // @ts-expect-error
+                            name,
+                            " does not exist",
+                        ];
+                        return [0, []];
+                    }
+                    for (const elem2 of constraints) {
+                        convertNameToId(elem2, false);
+                    }
+
+                    // @ts-expect-error
+                    return [this.typeNameIdMap.get(name).id, constraints];
+                }),
+            );
+        };
+
+        for (const elem of parsedQuery.elems) {
+            convertNameToId(elem, false);
+            this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
+        }
+        for (const elem of parsedQuery.returned) {
+            convertNameToId(elem, false);
+            this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
+        }
+
+
         /**
          * Creates the query results.
          *
-         * @param {Array<Result>} results_in_args
-         * @param {Array<Result>} results_returned
-         * @param {Array<Result>} results_others
-         * @param {ParsedQuery} parsedQuery
+         * @param {Array<rustdoc.ResultObject>} results_in_args
+         * @param {Array<rustdoc.ResultObject>} results_returned
+         * @param {Array<rustdoc.ResultObject>} results_others
+         * @param {rustdoc.ParsedQuery<rustdoc.QueryElement>} parsedQuery
          *
-         * @return {ResultsTable}
+         * @return {rustdoc.ResultsTable}
          */
         function createQueryResults(
             results_in_args,
@@ -2257,6 +2686,7 @@ class DocSearch {
             };
         }
 
+        // @ts-expect-error
         const buildHrefAndPath = item => {
             let displayPath;
             let href;
@@ -2320,6 +2750,7 @@ class DocSearch {
             return [displayPath, href, `${exactPath}::${name}`];
         };
 
+        // @ts-expect-error
         function pathSplitter(path) {
             const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
             if (tmp.endsWith("<span>")) {
@@ -2332,10 +2763,9 @@ class DocSearch {
          * Add extra data to result objects, and filter items that have been
          * marked for removal.
          *
-         * @param {[ResultObject]} results
+         * @param {[rustdoc.ResultObject]} results
          * @param {"sig"|"elems"|"returned"|null} typeInfo
-         * @param {ParsedQuery} query
-         * @returns {[ResultObject]}
+         * @returns {[rustdoc.ResultObject]}
          */
         const transformResults = (results, typeInfo) => {
             const duplicates = new Set();
@@ -2350,7 +2780,9 @@ class DocSearch {
                     }, this.searchIndex[result.id]);
 
                     // To be sure than it some items aren't considered as duplicate.
+                    // @ts-expect-error
                     obj.fullPath = res[2] + "|" + obj.ty;
+                    // @ts-expect-error
                     if (duplicates.has(obj.fullPath)) {
                         continue;
                     }
@@ -2363,14 +2795,18 @@ class DocSearch {
                     if (duplicates.has(res[2] + "|" + TY_IMPORT)) {
                         continue;
                     }
+                    // @ts-expect-error
                     duplicates.add(obj.fullPath);
                     duplicates.add(res[2]);
 
                     if (typeInfo !== null) {
+                        // @ts-expect-error
                         obj.displayTypeSignature =
+                            // @ts-expect-error
                             this.formatDisplayTypeSignature(obj, typeInfo);
                     }
 
+                    // @ts-expect-error
                     obj.href = res[1];
                     out.push(obj);
                     if (out.length >= MAX_RESULTS) {
@@ -2378,6 +2814,7 @@ class DocSearch {
                     }
                 }
             }
+            // @ts-expect-error
             return out;
         };
 
@@ -2388,30 +2825,34 @@ class DocSearch {
          * The output is formatted as an array of hunks, where odd numbered
          * hunks are highlighted and even numbered ones are not.
          *
-         * @param {ResultObject} obj
+         * @param {rustdoc.ResultObject} obj
          * @param {"sig"|"elems"|"returned"|null} typeInfo
-         * @param {ParsedQuery} query
-         * @returns Promise<
+         * @returns {Promise<{
          *   "type": Array<string>,
          *   "mappedNames": Map<string, string>,
          *   "whereClause": Map<string, Array<string>>,
-         * >
+         * }>}
          */
         this.formatDisplayTypeSignature = async(obj, typeInfo) => {
+            const objType = obj.type;
+            if (!objType) {
+                return {type: [], mappedNames: new Map(), whereClause: new Map()};
+            }
             let fnInputs = null;
             let fnOutput = null;
+            // @ts-expect-error
             let mgens = null;
             if (typeInfo !== "elems" && typeInfo !== "returned") {
                 fnInputs = unifyFunctionTypes(
-                    obj.type.inputs,
+                    objType.inputs,
                     parsedQuery.elems,
-                    obj.type.where_clause,
+                    objType.where_clause,
                     null,
                     mgensScratch => {
                         fnOutput = unifyFunctionTypes(
-                            obj.type.output,
+                            objType.output,
                             parsedQuery.returned,
-                            obj.type.where_clause,
+                            objType.where_clause,
                             mgensScratch,
                             mgensOut => {
                                 mgens = mgensOut;
@@ -2424,11 +2865,11 @@ class DocSearch {
                     0,
                 );
             } else {
-                const arr = typeInfo === "elems" ? obj.type.inputs : obj.type.output;
+                const arr = typeInfo === "elems" ? objType.inputs : objType.output;
                 const highlighted = unifyFunctionTypes(
                     arr,
                     parsedQuery.elems,
-                    obj.type.where_clause,
+                    objType.where_clause,
                     null,
                     mgensOut => {
                         mgens = mgensOut;
@@ -2443,15 +2884,16 @@ class DocSearch {
                 }
             }
             if (!fnInputs) {
-                fnInputs = obj.type.inputs;
+                fnInputs = objType.inputs;
             }
             if (!fnOutput) {
-                fnOutput = obj.type.output;
+                fnOutput = objType.output;
             }
             const mappedNames = new Map();
             const whereClause = new Map();
 
-            const fnParamNames = obj.paramNames;
+            const fnParamNames = obj.paramNames || [];
+            // @ts-expect-error
             const queryParamNames = [];
             /**
              * Recursively writes a map of IDs to query generic names,
@@ -2461,10 +2903,10 @@ class DocSearch {
              * mapping `(-1, "X")`, and the writeFn function looks up the entry
              * for -1 to form the final, user-visible mapping of "X is T".
              *
-             * @param {QueryElement} queryElem
+             * @param {rustdoc.QueryElement} queryElem
              */
             const remapQuery = queryElem => {
-                if (queryElem.id < 0) {
+                if (queryElem.id !== null && queryElem.id < 0) {
                     queryParamNames[-1 - queryElem.id] = queryElem.name;
                 }
                 if (queryElem.generics.length > 0) {
@@ -2483,7 +2925,7 @@ class DocSearch {
              * Index 0 is not highlighted, index 1 is highlighted,
              * index 2 is not highlighted, etc.
              *
-             * @param {{name: string, highlighted: bool|undefined}} fnType - input
+             * @param {{name?: string, highlighted?: boolean}} fnType - input
              * @param {[string]} result
              */
             const pushText = (fnType, result) => {
@@ -2496,6 +2938,7 @@ class DocSearch {
                 // needs coerced to a boolean.
                 if (!!(result.length % 2) === !!fnType.highlighted) {
                     result.push("");
+                // @ts-expect-error
                 } else if (result.length === 0 && !!fnType.highlighted) {
                     result.push("");
                     result.push("");
@@ -2508,7 +2951,7 @@ class DocSearch {
              * Write a higher order function type: either a function pointer
              * or a trait bound on Fn, FnMut, or FnOnce.
              *
-             * @param {FunctionType} fnType - input
+             * @param {rustdoc.HighlightedFunctionType} fnType - input
              * @param {[string]} result
              */
             const writeHof = (fnType, result) => {
@@ -2548,7 +2991,7 @@ class DocSearch {
              * Write a primitive type with special syntax, like `!` or `[T]`.
              * Returns `false` if the supplied type isn't special.
              *
-             * @param {FunctionType} fnType
+             * @param {rustdoc.HighlightedFunctionType} fnType
              * @param {[string]} result
              */
             const writeSpecialPrimitive = (fnType, result) => {
@@ -2563,6 +3006,7 @@ class DocSearch {
                     onEachBtwn(
                         fnType.generics,
                         nested => writeFn(nested, result),
+                        // @ts-expect-error
                         () => pushText({ name: ", ", highlighted: false }, result),
                     );
                     pushText({ name: sb, highlighted: fnType.highlighted }, result);
@@ -2573,9 +3017,10 @@ class DocSearch {
                     onEachBtwn(
                         fnType.generics,
                         value => {
-                            prevHighlighted = value.highlighted;
+                            prevHighlighted = !!value.highlighted;
                             writeFn(value, result);
                         },
+                        // @ts-expect-error
                         value => pushText({
                             name: " ",
                             highlighted: prevHighlighted && value.highlighted,
@@ -2593,25 +3038,27 @@ class DocSearch {
              * like slices, with their own formatting. It also handles
              * updating the where clause and generic type param map.
              *
-             * @param {FunctionType} fnType
+             * @param {rustdoc.HighlightedFunctionType} fnType
              * @param {[string]} result
              */
             const writeFn = (fnType, result) => {
-                if (fnType.id < 0) {
+                if (fnType.id !== null && fnType.id < 0) {
                     if (fnParamNames[-1 - fnType.id] === "") {
                         // Normally, there's no need to shown an unhighlighted
                         // where clause, but if it's impl Trait, then we do.
                         const generics = fnType.generics.length > 0 ?
                             fnType.generics :
-                            obj.type.where_clause[-1 - fnType.id];
+                            objType.where_clause[-1 - fnType.id];
                         for (const nested of generics) {
                             writeFn(nested, result);
                         }
                         return;
+                    // @ts-expect-error
                     } else if (mgens) {
                         for (const [queryId, fnId] of mgens) {
                             if (fnId === fnType.id) {
                                 mappedNames.set(
+                                    // @ts-expect-error
                                     queryParamNames[-1 - queryId],
                                     fnParamNames[-1 - fnType.id],
                                 );
@@ -2622,13 +3069,17 @@ class DocSearch {
                         name: fnParamNames[-1 - fnType.id],
                         highlighted: !!fnType.highlighted,
                     }, result);
+                    // @ts-expect-error
                     const where = [];
                     onEachBtwn(
                         fnType.generics,
+                        // @ts-expect-error
                         nested => writeFn(nested, where),
+                        // @ts-expect-error
                         () => pushText({ name: " + ", highlighted: false }, where),
                     );
                     if (where.length > 0) {
+                        // @ts-expect-error
                         whereClause.set(fnParamNames[-1 - fnType.id], where);
                     }
                 } else {
@@ -2650,12 +3101,15 @@ class DocSearch {
                             fnType.bindings,
                             ([key, values]) => {
                                 const name = this.assocTypeIdNameMap.get(key);
+                                // @ts-expect-error
                                 if (values.length === 1 && values[0].id < 0 &&
+                                    // @ts-expect-error
                                     `${fnType.name}::${name}` === fnParamNames[-1 - values[0].id]) {
                                     // the internal `Item=Iterator::Item` type variable should be
                                     // shown in the where clause and name mapping output, but is
                                     // redundant in this spot
                                     for (const value of values) {
+                                        // @ts-expect-error
                                         writeFn(value, []);
                                     }
                                     return true;
@@ -2672,12 +3126,14 @@ class DocSearch {
                                 onEachBtwn(
                                     values || [],
                                     value => writeFn(value, result),
+                                    // @ts-expect-error
                                     () => pushText({ name: " + ",  highlighted: false }, result),
                                 );
                                 if (values.length !== 1) {
                                     pushText({ name: ")", highlighted: false }, result);
                                 }
                             },
+                            // @ts-expect-error
                             () => pushText({ name: ", ",  highlighted: false }, result),
                         );
                     }
@@ -2687,6 +3143,7 @@ class DocSearch {
                     onEachBtwn(
                         fnType.generics,
                         value => writeFn(value, result),
+                        // @ts-expect-error
                         () => pushText({ name: ", ",  highlighted: false }, result),
                     );
                     if (hasBindings || fnType.generics.length > 0) {
@@ -2694,19 +3151,26 @@ class DocSearch {
                     }
                 }
             };
+            // @ts-expect-error
             const type = [];
             onEachBtwn(
                 fnInputs,
+                // @ts-expect-error
                 fnType => writeFn(fnType, type),
+                // @ts-expect-error
                 () => pushText({ name: ", ",  highlighted: false }, type),
             );
+            // @ts-expect-error
             pushText({ name: " -> ", highlighted: false }, type);
             onEachBtwn(
                 fnOutput,
+                // @ts-expect-error
                 fnType => writeFn(fnType, type),
+                // @ts-expect-error
                 () => pushText({ name: ", ",  highlighted: false }, type),
             );
 
+            // @ts-expect-error
             return {type, mappedNames, whereClause};
         };
 
@@ -2714,10 +3178,10 @@ class DocSearch {
          * This function takes a result map, and sorts it by various criteria, including edit
          * distance, substring match, and the crate it comes from.
          *
-         * @param {Results} results
-         * @param {boolean} isType
+         * @param {rustdoc.Results} results
+         * @param {"sig"|"elems"|"returned"|null} typeInfo
          * @param {string} preferredCrate
-         * @returns {Promise<[ResultObject]>}
+         * @returns {Promise<[rustdoc.ResultObject]>}
          */
         const sortResults = async(results, typeInfo, preferredCrate) => {
             const userQuery = parsedQuery.userQuery;
@@ -2733,12 +3197,12 @@ class DocSearch {
                     // we are doing a return-type based search,
                     // deprioritize "clone-like" results,
                     // ie. functions that also take the queried type as an argument.
-                    const hasType = result.item && result.item.type;
-                    if (!hasType) {
+                    const resultItemType = result.item && result.item.type;
+                    if (!resultItemType) {
                         continue;
                     }
-                    const inputs = result.item.type.inputs;
-                    const where_clause = result.item.type.where_clause;
+                    const inputs = resultItemType.inputs;
+                    const where_clause = resultItemType.where_clause;
                     if (containsTypeFromQuery(inputs, where_clause)) {
                         result.path_dist *= 100;
                         result.dist *= 100;
@@ -2748,35 +3212,38 @@ class DocSearch {
             }
 
             result_list.sort((aaa, bbb) => {
-                let a, b;
+                /** @type {number} */
+                let a;
+                /** @type {number} */
+                let b;
 
                 // sort by exact case-sensitive match
                 if (isMixedCase) {
-                    a = (aaa.item.name !== userQuery);
-                    b = (bbb.item.name !== userQuery);
+                    a = Number(aaa.item.name !== userQuery);
+                    b = Number(bbb.item.name !== userQuery);
                     if (a !== b) {
                         return a - b;
                     }
                 }
 
                 // sort by exact match with regard to the last word (mismatch goes later)
-                a = (aaa.word !== normalizedUserQuery);
-                b = (bbb.word !== normalizedUserQuery);
+                a = Number(aaa.word !== normalizedUserQuery);
+                b = Number(bbb.word !== normalizedUserQuery);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by index of keyword in item name (no literal occurrence goes later)
-                a = (aaa.index < 0);
-                b = (bbb.index < 0);
+                a = Number(aaa.index < 0);
+                b = Number(bbb.index < 0);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // in type based search, put functions first
                 if (parsedQuery.hasReturnArrow) {
-                    a = !isFnLikeTy(aaa.item.ty);
-                    b = !isFnLikeTy(bbb.item.ty);
+                    a = Number(!isFnLikeTy(aaa.item.ty));
+                    b = Number(!isFnLikeTy(bbb.item.ty));
                     if (a !== b) {
                         return a - b;
                     }
@@ -2784,80 +3251,93 @@ class DocSearch {
 
                 // Sort by distance in the path part, if specified
                 // (less changes required to match means higher rankings)
-                a = aaa.path_dist;
-                b = bbb.path_dist;
+                a = Number(aaa.path_dist);
+                b = Number(bbb.path_dist);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // (later literal occurrence, if any, goes later)
-                a = aaa.index;
-                b = bbb.index;
+                a = Number(aaa.index);
+                b = Number(bbb.index);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // Sort by distance in the name part, the last part of the path
                 // (less changes required to match means higher rankings)
-                a = (aaa.dist);
-                b = (bbb.dist);
+                a = Number(aaa.dist);
+                b = Number(bbb.dist);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort deprecated items later
-                a = this.searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex);
-                b = this.searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex);
+                a = Number(
+                    // @ts-expect-error
+                    this.searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex),
+                );
+                b = Number(
+                    // @ts-expect-error
+                    this.searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex),
+                );
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by crate (current crate comes first)
-                a = (aaa.item.crate !== preferredCrate);
-                b = (bbb.item.crate !== preferredCrate);
+                a = Number(aaa.item.crate !== preferredCrate);
+                b = Number(bbb.item.crate !== preferredCrate);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by item name length (longer goes later)
-                a = aaa.word.length;
-                b = bbb.word.length;
+                a = Number(aaa.word.length);
+                b = Number(bbb.word.length);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by item name (lexicographically larger goes later)
-                a = aaa.word;
-                b = bbb.word;
-                if (a !== b) {
-                    return (a > b ? +1 : -1);
+                let aw = aaa.word;
+                let bw = bbb.word;
+                if (aw !== bw) {
+                    return (aw > bw ? +1 : -1);
                 }
 
                 // sort by description (no description goes later)
-                a = this.searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex);
-                b = this.searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex);
+                a = Number(
+                    // @ts-expect-error
+                    this.searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex),
+                );
+                b = Number(
+                    // @ts-expect-error
+                    this.searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex),
+                );
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by type (later occurrence in `itemTypes` goes later)
-                a = aaa.item.ty;
-                b = bbb.item.ty;
+                a = Number(aaa.item.ty);
+                b = Number(bbb.item.ty);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by path (lexicographically larger goes later)
-                a = aaa.item.path;
-                b = bbb.item.path;
-                if (a !== b) {
-                    return (a > b ? +1 : -1);
+                aw = aaa.item.path;
+                bw = bbb.item.path;
+                if (aw !== bw) {
+                    return (aw > bw ? +1 : -1);
                 }
 
                 // que sera, sera
                 return 0;
             });
 
+            // @ts-expect-error
             return transformResults(result_list, typeInfo);
         };
 
@@ -2871,17 +3351,19 @@ class DocSearch {
          * then this function will try with a different solution, or bail with null if it
          * runs out of candidates.
          *
-         * @param {Array<FunctionType>} fnTypesIn - The objects to check.
-         * @param {Array<QueryElement>} queryElems - The elements from the parsed query.
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType[]} fnTypesIn - The objects to check.
+         * @param {rustdoc.QueryElement[]} queryElems - The elements from the parsed query.
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgensIn
          *     - Map query generics to function generics (never modified).
-         * @param {Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
+         * @param {function(Map<number,number>?): boolean} solutionCb
+         *     - Called for each `mgens` solution.
          * @param {number} unboxingDepth
          *     - Limit checks that Ty matches Vec<Ty>,
          *       but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
          *
-         * @return {[FunctionType]|null} - Returns highlighted results if a match, null otherwise.
+         * @return {rustdoc.HighlightedFunctionType[]|null}
+         *     - Returns highlighted results if a match, null otherwise.
          */
         function unifyFunctionTypes(
             fnTypesIn,
@@ -2895,7 +3377,7 @@ class DocSearch {
                 return null;
             }
             /**
-             * @type Map<integer, integer>|null
+             * @type {Map<number, number>|null}
              */
             const mgens = mgensIn === null ? null : new Map(mgensIn);
             if (queryElems.length === 0) {
@@ -2915,7 +3397,11 @@ class DocSearch {
                     if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
                         continue;
                     }
-                    if (fnType.id < 0 && queryElem.id < 0) {
+                    if (fnType.id !== null &&
+                        fnType.id < 0 &&
+                        queryElem.id !== null &&
+                        queryElem.id < 0
+                    ) {
                         if (mgens && mgens.has(queryElem.id) &&
                             mgens.get(queryElem.id) !== fnType.id) {
                             continue;
@@ -2959,8 +3445,10 @@ class DocSearch {
                     )) {
                         continue;
                     }
+                    // @ts-expect-error
                     if (fnType.id < 0) {
                         const highlightedGenerics = unifyFunctionTypes(
+                            // @ts-expect-error
                             whereClause[(-fnType.id) - 1],
                             queryElems,
                             whereClause,
@@ -2998,12 +3486,13 @@ class DocSearch {
                         }
                     }
                 }
+                // @ts-expect-error
                 return false;
             }
 
             // Multiple element recursive case
             /**
-             * @type Array<FunctionType>
+             * @type {Array<rustdoc.FunctionType>}
              */
             const fnTypes = fnTypesIn.slice();
             /**
@@ -3033,7 +3522,7 @@ class DocSearch {
                     continue;
                 }
                 let mgensScratch;
-                if (fnType.id < 0) {
+                if (fnType.id !== null && queryElem.id !== null && fnType.id < 0) {
                     mgensScratch = new Map(mgens);
                     if (mgensScratch.has(queryElem.id)
                         && mgensScratch.get(queryElem.id) !== fnType.id) {
@@ -3052,8 +3541,11 @@ class DocSearch {
                 if (!queryElemsTmp) {
                     queryElemsTmp = queryElems.slice(0, qlast);
                 }
+                /** @type {rustdoc.HighlightedFunctionType[]|null} */
                 let unifiedGenerics = [];
+                // @ts-expect-error
                 let unifiedGenericsMgens = null;
+                /** @type {rustdoc.HighlightedFunctionType[]|null} */
                 const passesUnification = unifyFunctionTypes(
                     fnTypes,
                     queryElemsTmp,
@@ -3102,11 +3594,14 @@ class DocSearch {
                         bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
                             return [k, queryElem.bindings.has(k) ? unifyFunctionTypes(
                                 v,
+                                // @ts-expect-error
                                 queryElem.bindings.get(k),
                                 whereClause,
+                                // @ts-expect-error
                                 unifiedGenericsMgens,
                                 solutionCb,
                                 unboxingDepth,
+                            // @ts-expect-error
                             ) : unifiedGenerics.splice(0, v.length)];
                         })),
                     });
@@ -3128,7 +3623,7 @@ class DocSearch {
                 )) {
                     continue;
                 }
-                const generics = fnType.id < 0 ?
+                const generics = fnType.id !== null && fnType.id < 0 ?
                     whereClause[(-fnType.id) - 1] :
                     fnType.generics;
                 const bindings = fnType.bindings ?
@@ -3171,17 +3666,19 @@ class DocSearch {
          * `Vec` of `Allocators` and not the implicit `Allocator` parameter that every
          * `Vec` has.
          *
-         * @param {Array<FunctionType>} fnTypesIn - The objects to check.
-         * @param {Array<QueryElement>} queryElems - The elements from the parsed query.
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {Array<rustdoc.FunctionType>} fnTypesIn - The objects to check.
+         * @param {Array<rustdoc.QueryElement>} queryElems - The elements from the parsed query.
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgensIn
          *     - Map functions generics to query generics (never modified).
-         * @param {Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
+         * @param {function(Map<number,number>): boolean} solutionCb
+         *     - Called for each `mgens` solution.
          * @param {number} unboxingDepth
          *     - Limit checks that Ty matches Vec<Ty>,
          *       but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
          *
-         * @return {[FunctionType]|null} - Returns highlighted results if a match, null otherwise.
+         * @return {rustdoc.HighlightedFunctionType[]|null}
+         *     - Returns highlighted results if a match, null otherwise.
          */
         function unifyGenericTypes(
             fnTypesIn,
@@ -3195,10 +3692,11 @@ class DocSearch {
                 return null;
             }
             /**
-             * @type Map<integer, integer>|null
+             * @type {Map<number, number>|null}
              */
             const mgens = mgensIn === null ? null : new Map(mgensIn);
             if (queryElems.length === 0) {
+                // @ts-expect-error
                 return solutionCb(mgens) ? fnTypesIn : null;
             }
             if (!fnTypesIn || fnTypesIn.length === 0) {
@@ -3207,7 +3705,11 @@ class DocSearch {
             const fnType = fnTypesIn[0];
             const queryElem = queryElems[0];
             if (unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
-                if (fnType.id < 0 && queryElem.id < 0) {
+                if (fnType.id !== null &&
+                    fnType.id < 0 &&
+                    queryElem.id !== null &&
+                    queryElem.id < 0
+                ) {
                     if (!mgens || !mgens.has(queryElem.id) ||
                         mgens.get(queryElem.id) === fnType.id
                     ) {
@@ -3238,6 +3740,7 @@ class DocSearch {
                         queryElems.slice(1),
                         whereClause,
                         mgens,
+                        // @ts-expect-error
                         mgensScratch => {
                             const solution = unifyFunctionTypeCheckBindings(
                                 fnType,
@@ -3285,7 +3788,7 @@ class DocSearch {
                 unboxingDepth + 1,
             )) {
                 let highlightedRemaining;
-                if (fnType.id < 0) {
+                if (fnType.id !== null && fnType.id < 0) {
                     // Where clause corresponds to `F: A + B`
                     //                                 ^^^^^
                     // The order of the constraints doesn't matter, so
@@ -3295,6 +3798,7 @@ class DocSearch {
                         [queryElem],
                         whereClause,
                         mgens,
+                        // @ts-expect-error
                         mgensScratch => {
                             const hl = unifyGenericTypes(
                                 fnTypesIn.slice(1),
@@ -3316,6 +3820,7 @@ class DocSearch {
                             highlighted: true,
                         }, fnType, {
                             generics: highlightedGenerics,
+                        // @ts-expect-error
                         }), ...highlightedRemaining];
                     }
                 } else {
@@ -3327,6 +3832,7 @@ class DocSearch {
                         [queryElem],
                         whereClause,
                         mgens,
+                        // @ts-expect-error
                         mgensScratch => {
                             const hl = unifyGenericTypes(
                                 fnTypesIn.slice(1),
@@ -3349,6 +3855,7 @@ class DocSearch {
                             bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
                                 return [k, highlightedGenerics.splice(0, v.length)];
                             })),
+                        // @ts-expect-error
                         }), ...highlightedRemaining];
                     }
                 }
@@ -3364,8 +3871,8 @@ class DocSearch {
          * or associated type bindings: that's not load-bearing, but it prevents unnecessary
          * backtracking later.
          *
-         * @param {FunctionType} fnType
-         * @param {QueryElement} queryElem
+         * @param {rustdoc.FunctionType} fnType
+         * @param {rustdoc.QueryElement} queryElem
          * @param {Map<number,number>|null} mgensIn - Map query generics to function generics.
          * @returns {boolean}
          */
@@ -3377,7 +3884,7 @@ class DocSearch {
             // fnType.id < 0 means generic
             // queryElem.id < 0 does too
             // mgensIn[queryElem.id] = fnType.id
-            if (fnType.id < 0 && queryElem.id < 0) {
+            if (fnType.id !== null && fnType.id < 0 && queryElem.id !== null && queryElem.id < 0) {
                 if (
                     mgensIn && mgensIn.has(queryElem.id) &&
                     mgensIn.get(queryElem.id) !== fnType.id
@@ -3456,13 +3963,15 @@ class DocSearch {
          * ID of u32 in it, and the rest of the matching engine acts as if `Iterator<u32>` were
          * the type instead.
          *
-         * @param {FunctionType} fnType
-         * @param {QueryElement} queryElem
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
-         * @param {Map<number,number>} mgensIn - Map query generics to function generics.
+         * @param {rustdoc.FunctionType} fnType
+         * @param {rustdoc.QueryElement} queryElem
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
+         * @param {Map<number,number>|null} mgensIn - Map query generics to function generics.
          *                                            Never modified.
          * @param {number} unboxingDepth
-         * @returns {false|{mgens: [Map<number,number>], simplifiedGenerics: [FunctionType]}}
+         * @returns {false|{
+         *     mgens: [Map<number,number>|null], simplifiedGenerics: rustdoc.FunctionType[]
+         * }}
          */
         function unifyFunctionTypeCheckBindings(
             fnType,
@@ -3486,8 +3995,10 @@ class DocSearch {
                     }
                     const fnTypeBindings = fnType.bindings.get(name);
                     mgensSolutionSet = mgensSolutionSet.flatMap(mgens => {
+                        // @ts-expect-error
                         const newSolutions = [];
                         unifyFunctionTypes(
+                            // @ts-expect-error
                             fnTypeBindings,
                             constraints,
                             whereClause,
@@ -3500,6 +4011,7 @@ class DocSearch {
                             },
                             unboxingDepth,
                         );
+                        // @ts-expect-error
                         return newSolutions;
                     });
                 }
@@ -3519,14 +4031,15 @@ class DocSearch {
                 } else {
                     simplifiedGenerics = binds;
                 }
+                // @ts-expect-error
                 return { simplifiedGenerics, mgens: mgensSolutionSet };
             }
             return { simplifiedGenerics, mgens: [mgensIn] };
         }
         /**
-         * @param {FunctionType} fnType
-         * @param {QueryElement} queryElem
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType} fnType
+         * @param {rustdoc.QueryElement} queryElem
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map query generics to function generics.
          * @param {number} unboxingDepth
          * @returns {boolean}
@@ -3541,7 +4054,7 @@ class DocSearch {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
             }
-            if (fnType.id < 0) {
+            if (fnType.id !== null && fnType.id < 0) {
                 if (!whereClause) {
                     return false;
                 }
@@ -3577,14 +4090,14 @@ class DocSearch {
          * This function checks if the given list contains any
          * (non-generic) types mentioned in the query.
          *
-         * @param {Array<FunctionType>} list    - A list of function types.
-         * @param {[FunctionType]} where_clause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType[]} list    - A list of function types.
+         * @param {rustdoc.FunctionType[][]} where_clause - Trait bounds for generic items.
          */
         function containsTypeFromQuery(list, where_clause) {
             if (!list) return false;
             for (const ty of parsedQuery.returned) {
                 // negative type ids are generics
-                if (ty.id < 0) {
+                if (ty.id !== null && ty.id < 0) {
                     continue;
                 }
                 if (checkIfInList(list, ty, where_clause, null, 0)) {
@@ -3592,7 +4105,7 @@ class DocSearch {
                 }
             }
             for (const ty of parsedQuery.elems) {
-                if (ty.id < 0) {
+                if (ty.id !== null && ty.id < 0) {
                     continue;
                 }
                 if (checkIfInList(list, ty, where_clause, null, 0)) {
@@ -3606,9 +4119,9 @@ class DocSearch {
          * This function checks if the object (`row`) matches the given type (`elem`) and its
          * generics (if any).
          *
-         * @param {Array<FunctionType>} list
-         * @param {QueryElement} elem          - The element from the parsed query.
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType[]} list
+         * @param {rustdoc.QueryElement} elem          - The element from the parsed query.
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
          * @param {number} unboxingDepth
          *
@@ -3627,18 +4140,20 @@ class DocSearch {
          * This function checks if the object (`row`) matches the given type (`elem`) and its
          * generics (if any).
          *
-         * @param {Row} row
-         * @param {QueryElement} elem          - The element from the parsed query.
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType} row
+         * @param {rustdoc.QueryElement} elem          - The element from the parsed query.
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map query generics to function generics.
          *
          * @return {boolean} - Returns true if the type matches, false otherwise.
          */
+        // @ts-expect-error
         const checkType = (row, elem, whereClause, mgens, unboxingDepth) => {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
             }
-            if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
+            if (row.id !== null && elem.id !== null &&
+                row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
                 row.generics.length === 0 && elem.generics.length === 0 &&
                 row.bindings.size === 0 && elem.bindings.size === 0 &&
                 // special case
@@ -3648,6 +4163,7 @@ class DocSearch {
             ) {
                 return row.id === elem.id && typePassesFilter(elem.typeFilter, row.ty);
             } else {
+                // @ts-expect-error
                 return unifyFunctionTypes(
                     [row],
                     [elem],
@@ -3662,6 +4178,7 @@ class DocSearch {
         /**
          * Check a query solution for conflicting generics.
          */
+        // @ts-expect-error
         const checkTypeMgensForConflict = mgens => {
             if (!mgens) {
                 return true;
@@ -3679,7 +4196,7 @@ class DocSearch {
         /**
          * Compute an "edit distance" that ignores missing path elements.
          * @param {string[]} contains search query path
-         * @param {Row} ty indexed item
+         * @param {rustdoc.Row} ty indexed item
          * @returns {null|number} edit distance
          */
         function checkPath(contains, ty) {
@@ -3720,6 +4237,7 @@ class DocSearch {
             return ret_dist > maxPathEditDistance ? null : ret_dist;
         }
 
+        // @ts-expect-error
         function typePassesFilter(filter, type) {
             // No filter or Exact mach
             if (filter <= NO_TYPE_FILTER || filter === type) return true;
@@ -3741,6 +4259,7 @@ class DocSearch {
             return false;
         }
 
+        // @ts-expect-error
         function createAliasFromItem(item) {
             return {
                 crate: item.crate,
@@ -3758,11 +4277,14 @@ class DocSearch {
             };
         }
 
+        // @ts-expect-error
         const handleAliases = async(ret, query, filterCrates, currentCrate) => {
             const lowerQuery = query.toLowerCase();
             // We separate aliases and crate aliases because we want to have current crate
             // aliases to be before the others in the displayed results.
+            // @ts-expect-error
             const aliases = [];
+            // @ts-expect-error
             const crateAliases = [];
             if (filterCrates !== null) {
                 if (this.ALIASES.has(filterCrates)
@@ -3775,6 +4297,7 @@ class DocSearch {
             } else {
                 for (const [crate, crateAliasesIndex] of this.ALIASES) {
                     if (crateAliasesIndex.has(lowerQuery)) {
+                        // @ts-expect-error
                         const pushTo = crate === currentCrate ? crateAliases : aliases;
                         const query_aliases = crateAliasesIndex.get(lowerQuery);
                         for (const alias of query_aliases) {
@@ -3784,6 +4307,7 @@ class DocSearch {
                 }
             }
 
+            // @ts-expect-error
             const sortFunc = (aaa, bbb) => {
                 if (aaa.path < bbb.path) {
                     return 1;
@@ -3792,18 +4316,23 @@ class DocSearch {
                 }
                 return -1;
             };
+            // @ts-expect-error
             crateAliases.sort(sortFunc);
             aliases.sort(sortFunc);
 
+            // @ts-expect-error
             const fetchDesc = alias => {
+                // @ts-expect-error
                 return this.searchIndexEmptyDesc.get(alias.crate).contains(alias.bitIndex) ?
                     "" : this.searchState.loadDesc(alias);
             };
             const [crateDescs, descs] = await Promise.all([
+                // @ts-expect-error
                 Promise.all(crateAliases.map(fetchDesc)),
                 Promise.all(aliases.map(fetchDesc)),
             ]);
 
+            // @ts-expect-error
             const pushFunc = alias => {
                 alias.alias = query;
                 const res = buildHrefAndPath(alias);
@@ -3818,12 +4347,15 @@ class DocSearch {
             };
 
             aliases.forEach((alias, i) => {
+                // @ts-expect-error
                 alias.desc = descs[i];
             });
             aliases.forEach(pushFunc);
+            // @ts-expect-error
             crateAliases.forEach((alias, i) => {
                 alias.desc = crateDescs[i];
             });
+            // @ts-expect-error
             crateAliases.forEach(pushFunc);
         };
 
@@ -3843,21 +4375,24 @@ class DocSearch {
          * * `path_dist` is zero if a single-component search query is used, otherwise it's the
          *   distance computed for everything other than the last path component.
          *
-         * @param {Results} results
+         * @param {rustdoc.Results} results
          * @param {string} fullId
-         * @param {integer} id
-         * @param {integer} index
-         * @param {integer} dist
-         * @param {integer} path_dist
+         * @param {number} id
+         * @param {number} index
+         * @param {number} dist
+         * @param {number} path_dist
          */
+        // @ts-expect-error
         function addIntoResults(results, fullId, id, index, dist, path_dist, maxEditDistance) {
             if (dist <= maxEditDistance || index !== -1) {
                 if (results.has(fullId)) {
                     const result = results.get(fullId);
+                    // @ts-expect-error
                     if (result.dontValidate || result.dist <= dist) {
                         return;
                     }
                 }
+                // @ts-expect-error
                 results.set(fullId, {
                     id: id,
                     index: index,
@@ -3873,12 +4408,16 @@ class DocSearch {
          * try to match the items which validates all the elements. For `aa -> bb` will look for
          * functions which have a parameter `aa` and has `bb` in its returned values.
          *
-         * @param {Row} row
-         * @param {integer} pos      - Position in the `searchIndex`.
-         * @param {Object} results
+         * @param {rustdoc.Row} row
+         * @param {number} pos      - Position in the `searchIndex`.
+         * @param {rustdoc.Results} results
          */
         function handleArgs(row, pos, results) {
-            if (!row || (filterCrates !== null && row.crate !== filterCrates) || !row.type) {
+            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+                return;
+            }
+            const rowType = row.type;
+            if (!rowType) {
                 return;
             }
 
@@ -3889,21 +4428,23 @@ class DocSearch {
             if (tfpDist === null) {
                 return;
             }
+            // @ts-expect-error
             if (results.size >= MAX_RESULTS && tfpDist > results.max_dist) {
                 return;
             }
 
             // If the result is too "bad", we return false and it ends this search.
             if (!unifyFunctionTypes(
-                row.type.inputs,
+                rowType.inputs,
                 parsedQuery.elems,
-                row.type.where_clause,
+                rowType.where_clause,
                 null,
+                // @ts-expect-error
                 mgens => {
                     return unifyFunctionTypes(
-                        row.type.output,
+                        rowType.output,
                         parsedQuery.returned,
-                        row.type.where_clause,
+                        rowType.where_clause,
                         mgens,
                         checkTypeMgensForConflict,
                         0, // unboxing depth
@@ -3914,15 +4455,16 @@ class DocSearch {
                 return;
             }
 
+            // @ts-expect-error
             results.max_dist = Math.max(results.max_dist || 0, tfpDist);
-            addIntoResults(results, row.id, pos, 0, tfpDist, 0, Number.MAX_VALUE);
+            addIntoResults(results, row.id.toString(), pos, 0, tfpDist, 0, Number.MAX_VALUE);
         }
 
         /**
          * Compare the query fingerprint with the function fingerprint.
          *
-         * @param {{number}} fullId - The function
-         * @param {{Uint32Array}} queryFingerprint - The query
+         * @param {number} fullId - The function
+         * @param {Uint32Array} queryFingerprint - The query
          * @returns {number|null} - Null if non-match, number if distance
          *                          This function might return 0!
          */
@@ -3953,138 +4495,10 @@ class DocSearch {
 
 
         const innerRunQuery = () => {
-            const queryLen =
-                parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
-                parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
-            const maxEditDistance = Math.floor(queryLen / 3);
-
-            /**
-             * @type {Map<string, integer>}
-             */
-            const genericSymbols = new Map();
-
-            /**
-             * Convert names to ids in parsed query elements.
-             * This is not used for the "In Names" tab, but is used for the
-             * "In Params", "In Returns", and "In Function Signature" tabs.
-             *
-             * If there is no matching item, but a close-enough match, this
-             * function also that correction.
-             *
-             * See `buildTypeMapIndex` for more information.
-             *
-             * @param {QueryElement} elem
-             * @param {boolean} isAssocType
-             */
-            const convertNameToId = (elem, isAssocType) => {
-                const loweredName = elem.pathLast.toLowerCase();
-                if (this.typeNameIdMap.has(loweredName) &&
-                    (isAssocType || !this.typeNameIdMap.get(loweredName).assocOnly)) {
-                    elem.id = this.typeNameIdMap.get(loweredName).id;
-                } else if (!parsedQuery.literalSearch) {
-                    let match = null;
-                    let matchDist = maxEditDistance + 1;
-                    let matchName = "";
-                    for (const [name, { id, assocOnly }] of this.typeNameIdMap) {
-                        const dist = Math.min(
-                            editDistance(name, loweredName, maxEditDistance),
-                            editDistance(name, elem.normalizedPathLast, maxEditDistance),
-                        );
-                        if (dist <= matchDist && dist <= maxEditDistance &&
-                            (isAssocType || !assocOnly)) {
-                            if (dist === matchDist && matchName > name) {
-                                continue;
-                            }
-                            match = id;
-                            matchDist = dist;
-                            matchName = name;
-                        }
-                    }
-                    if (match !== null) {
-                        parsedQuery.correction = matchName;
-                    }
-                    elem.id = match;
-                }
-                if ((elem.id === null && parsedQuery.totalElems > 1 && elem.typeFilter === -1
-                    && elem.generics.length === 0 && elem.bindings.size === 0)
-                    || elem.typeFilter === TY_GENERIC) {
-                    if (genericSymbols.has(elem.normalizedPathLast)) {
-                        elem.id = genericSymbols.get(elem.normalizedPathLast);
-                    } else {
-                        elem.id = -(genericSymbols.size + 1);
-                        genericSymbols.set(elem.normalizedPathLast, elem.id);
-                    }
-                    if (elem.typeFilter === -1 && elem.normalizedPathLast.length >= 3) {
-                        // Silly heuristic to catch if the user probably meant
-                        // to not write a generic parameter. We don't use it,
-                        // just bring it up.
-                        const maxPartDistance = Math.floor(elem.normalizedPathLast.length / 3);
-                        let matchDist = maxPartDistance + 1;
-                        let matchName = "";
-                        for (const name of this.typeNameIdMap.keys()) {
-                            const dist = editDistance(
-                                name,
-                                elem.normalizedPathLast,
-                                maxPartDistance,
-                            );
-                            if (dist <= matchDist && dist <= maxPartDistance) {
-                                if (dist === matchDist && matchName > name) {
-                                    continue;
-                                }
-                                matchDist = dist;
-                                matchName = name;
-                            }
-                        }
-                        if (matchName !== "") {
-                            parsedQuery.proposeCorrectionFrom = elem.name;
-                            parsedQuery.proposeCorrectionTo = matchName;
-                        }
-                    }
-                    elem.typeFilter = TY_GENERIC;
-                }
-                if (elem.generics.length > 0 && elem.typeFilter === TY_GENERIC) {
-                    // Rust does not have HKT
-                    parsedQuery.error = [
-                        "Generic type parameter ",
-                        elem.name,
-                        " does not accept generic parameters",
-                    ];
-                }
-                for (const elem2 of elem.generics) {
-                    convertNameToId(elem2);
-                }
-                elem.bindings = new Map(Array.from(elem.bindings.entries())
-                    .map(entry => {
-                        const [name, constraints] = entry;
-                        if (!this.typeNameIdMap.has(name)) {
-                            parsedQuery.error = [
-                                "Type parameter ",
-                                name,
-                                " does not exist",
-                            ];
-                            return [null, []];
-                        }
-                        for (const elem2 of constraints) {
-                            convertNameToId(elem2);
-                        }
-
-                        return [this.typeNameIdMap.get(name).id, constraints];
-                    }),
-                );
-            };
-
-            for (const elem of parsedQuery.elems) {
-                convertNameToId(elem);
-                this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
-            }
-            for (const elem of parsedQuery.returned) {
-                convertNameToId(elem);
-                this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
-            }
-
             if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
                 const elem = parsedQuery.elems[0];
                 // use arrow functions to preserve `this`.
+                // @ts-expect-error
                 const handleNameSearch = id => {
                     const row = this.searchIndex[id];
                     if (!typePassesFilter(elem.typeFilter, row.ty) ||
@@ -4094,6 +4508,7 @@ class DocSearch {
 
                     let pathDist = 0;
                     if (elem.fullPath.length > 1) {
+                        // @ts-expect-error
                         pathDist = checkPath(elem.pathWithoutLast, row);
                         if (pathDist === null) {
                             return;
@@ -4102,11 +4517,13 @@ class DocSearch {
 
                     if (parsedQuery.literalSearch) {
                         if (row.word === elem.pathLast) {
+                            // @ts-expect-error
                             addIntoResults(results_others, row.id, id, 0, 0, pathDist);
                         }
                     } else {
                         addIntoResults(
                             results_others,
+                            // @ts-expect-error
                             row.id,
                             id,
                             row.normalizedName.indexOf(elem.normalizedPathLast),
@@ -4147,23 +4564,31 @@ class DocSearch {
                         const returned = row.type && row.type.output
                             && checkIfInList(row.type.output, elem, row.type.where_clause, null, 0);
                         if (in_args) {
+                            // @ts-expect-error
                             results_in_args.max_dist = Math.max(
+                                // @ts-expect-error
                                 results_in_args.max_dist || 0,
                                 tfpDist,
                             );
                             const maxDist = results_in_args.size < MAX_RESULTS ?
                                 (tfpDist + 1) :
+                                // @ts-expect-error
                                 results_in_args.max_dist;
+                            // @ts-expect-error
                             addIntoResults(results_in_args, row.id, i, -1, tfpDist, 0, maxDist);
                         }
                         if (returned) {
+                            // @ts-expect-error
                             results_returned.max_dist = Math.max(
+                                // @ts-expect-error
                                 results_returned.max_dist || 0,
                                 tfpDist,
                             );
                             const maxDist = results_returned.size < MAX_RESULTS ?
                                 (tfpDist + 1) :
+                                // @ts-expect-error
                                 results_returned.max_dist;
+                            // @ts-expect-error
                             addIntoResults(results_returned, row.id, i, -1, tfpDist, 0, maxDist);
                         }
                     }
@@ -4173,14 +4598,17 @@ class DocSearch {
                 // types with generic parameters go last.
                 // That's because of the way unification is structured: it eats off
                 // the end, and hits a fast path if the last item is a simple atom.
+                // @ts-expect-error
                 const sortQ = (a, b) => {
                     const ag = a.generics.length === 0 && a.bindings.size === 0;
                     const bg = b.generics.length === 0 && b.bindings.size === 0;
                     if (ag !== bg) {
+                        // @ts-expect-error
                         return ag - bg;
                     }
                     const ai = a.id > 0;
                     const bi = b.id > 0;
+                    // @ts-expect-error
                     return ai - bi;
                 };
                 parsedQuery.elems.sort(sortQ);
@@ -4197,8 +4625,11 @@ class DocSearch {
 
         const isType = parsedQuery.foundElems !== 1 || parsedQuery.hasReturnArrow;
         const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([
+            // @ts-expect-error
             sortResults(results_in_args, "elems", currentCrate),
+            // @ts-expect-error
             sortResults(results_returned, "returned", currentCrate),
+            // @ts-expect-error
             sortResults(results_others, (isType ? "query" : null), currentCrate),
         ]);
         const ret = createQueryResults(
@@ -4210,11 +4641,14 @@ class DocSearch {
             filterCrates, currentCrate);
         await Promise.all([ret.others, ret.returned, ret.in_args].map(async list => {
             const descs = await Promise.all(list.map(result => {
+                // @ts-expect-error
                 return this.searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex) ?
                     "" :
+                    // @ts-expect-error
                     this.searchState.loadDesc(result);
             }));
             for (const [i, result] of list.entries()) {
+                // @ts-expect-error
                 result.desc = descs[i];
             }
         }));
@@ -4229,7 +4663,9 @@ class DocSearch {
 
 // ==================== Core search logic end ====================
 
+/** @type {Map<string, rustdoc.RawSearchIndexCrate>} */
 let rawSearchIndex;
+// @ts-expect-error
 let docSearch;
 const longItemTypes = [
     "keyword",
@@ -4259,13 +4695,16 @@ const longItemTypes = [
     "derive macro",
     "trait alias",
 ];
+// @ts-expect-error
 let currentResults;
 
 // In the search display, allows to switch between tabs.
+// @ts-expect-error
 function printTab(nb) {
     let iter = 0;
     let foundCurrentTab = false;
     let foundCurrentResultSet = false;
+    // @ts-expect-error
     onEachLazy(document.getElementById("search-tabs").childNodes, elem => {
         if (nb === iter) {
             addClass(elem, "selected");
@@ -4277,6 +4716,7 @@ function printTab(nb) {
     });
     const isTypeSearch = (nb > 0 || iter === 1);
     iter = 0;
+    // @ts-expect-error
     onEachLazy(document.getElementById("results").childNodes, elem => {
         if (nb === iter) {
             addClass(elem, "active");
@@ -4287,12 +4727,15 @@ function printTab(nb) {
         iter += 1;
     });
     if (foundCurrentTab && foundCurrentResultSet) {
+        // @ts-expect-error
         searchState.currentTab = nb;
         // Corrections only kick in on type-based searches.
         const correctionsElem = document.getElementsByClassName("search-corrections");
         if (isTypeSearch) {
+            // @ts-expect-error
             removeClass(correctionsElem[0], "hidden");
         } else {
+            // @ts-expect-error
             addClass(correctionsElem[0], "hidden");
         }
     } else if (nb !== 0) {
@@ -4326,16 +4769,22 @@ function getFilterCrates() {
     const elem = document.getElementById("crate-search");
 
     if (elem &&
+        // @ts-expect-error
         elem.value !== "all crates" &&
+        // @ts-expect-error
         window.searchIndex.has(elem.value)
     ) {
+        // @ts-expect-error
         return elem.value;
     }
     return null;
 }
 
+// @ts-expect-error
 function nextTab(direction) {
+    // @ts-expect-error
     const next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
+    // @ts-expect-error
     searchState.focusedByTab[searchState.currentTab] = document.activeElement;
     printTab(next);
     focusSearchResult();
@@ -4344,9 +4793,12 @@ function nextTab(direction) {
 // Focus the first search result on the active tab, or the result that
 // was focused last time this tab was active.
 function focusSearchResult() {
+    // @ts-expect-error
     const target = searchState.focusedByTab[searchState.currentTab] ||
         document.querySelectorAll(".search-results.active a").item(0) ||
+        // @ts-expect-error
         document.querySelectorAll("#search-tabs button").item(searchState.currentTab);
+    // @ts-expect-error
     searchState.focusedByTab[searchState.currentTab] = null;
     if (target) {
         target.focus();
@@ -4356,9 +4808,8 @@ function focusSearchResult() {
 /**
  * Render a set of search results for a single tab.
  * @param {Array<?>}    array   - The search results for this tab
- * @param {ParsedQuery} query
+ * @param {rustdoc.ParsedQuery<rustdoc.QueryElement>} query
  * @param {boolean}     display - True if this is the active tab
- * @param {"sig"|"elems"|"returned"|null} typeInfo
  */
 async function addTab(array, query, display) {
     const extraClass = display ? " active" : "";
@@ -4405,6 +4856,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             if (item.displayTypeSignature) {
                 const {type, mappedNames, whereClause} = await item.displayTypeSignature;
                 const displayType = document.createElement("div");
+                // @ts-expect-error
                 type.forEach((value, index) => {
                     if (index % 2 !== 0) {
                         const highlight = document.createElement("strong");
@@ -4445,6 +4897,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
                         const line = document.createElement("div");
                         line.className = "where";
                         line.appendChild(document.createTextNode(`    ${name}: `));
+                        // @ts-expect-error
                         innerType.forEach((value, index) => {
                             if (index % 2 !== 0) {
                                 const highlight = document.createElement("strong");
@@ -4488,6 +4941,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
     return output;
 }
 
+// @ts-expect-error
 function makeTabHeader(tabNb, text, nbElems) {
     // https://blog.horizon-eda.org/misc/2020/02/19/ui.html
     //
@@ -4497,6 +4951,7 @@ function makeTabHeader(tabNb, text, nbElems) {
     const fmtNbElems =
         nbElems < 10  ? `\u{2007}(${nbElems})\u{2007}\u{2007}` :
         nbElems < 100 ? `\u{2007}(${nbElems})\u{2007}` : `\u{2007}(${nbElems})`;
+    // @ts-expect-error
     if (searchState.currentTab === tabNb) {
         return "<button class=\"selected\">" + text +
             "<span class=\"count\">" + fmtNbElems + "</span></button>";
@@ -4505,11 +4960,12 @@ function makeTabHeader(tabNb, text, nbElems) {
 }
 
 /**
- * @param {ResultsTable} results
+ * @param {rustdoc.ResultsTable} results
  * @param {boolean} go_to_first
  * @param {string} filterCrates
  */
 async function showResults(results, go_to_first, filterCrates) {
+    // @ts-expect-error
     const search = searchState.outputElement();
     if (go_to_first || (results.others.length === 1
         && getSettingValue("go-to-only-result") === "true")
@@ -4527,6 +4983,7 @@ async function showResults(results, go_to_first, filterCrates) {
         // will be used, starting search again since the search input is not empty, leading you
         // back to the previous page again.
         window.onunload = () => { };
+        // @ts-expect-error
         searchState.removeQueryParameters();
         const elem = document.createElement("a");
         elem.href = results.others[0].href;
@@ -4537,6 +4994,7 @@ async function showResults(results, go_to_first, filterCrates) {
         return;
     }
     if (results.query === undefined) {
+        // @ts-expect-error
         results.query = DocSearch.parseQuery(searchState.input.value);
     }
 
@@ -4545,6 +5003,7 @@ async function showResults(results, go_to_first, filterCrates) {
     // 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
     // it again.
+    // @ts-expect-error
     let currentTab = searchState.currentTab;
     if ((currentTab === 0 && results.others.length === 0) ||
         (currentTab === 1 && results.in_args.length === 0) ||
@@ -4572,6 +5031,7 @@ async function showResults(results, go_to_first, filterCrates) {
         <h1 class="search-results-title">Results</h1>${crates}</div>`;
     if (results.query.error !== null) {
         const error = results.query.error;
+        // @ts-expect-error
         error.forEach((value, index) => {
             value = value.split("<").join("&lt;").split(">").join("&gt;");
             if (index % 2 !== 0) {
@@ -4632,7 +5092,9 @@ async function showResults(results, go_to_first, filterCrates) {
     resultsElem.appendChild(ret_returned);
 
     search.innerHTML = output;
+    // @ts-expect-error
     if (searchState.rustdocToolbar) {
+        // @ts-expect-error
         search.querySelector(".main-heading").appendChild(searchState.rustdocToolbar);
     }
     const crateSearch = document.getElementById("crate-search");
@@ -4641,23 +5103,30 @@ async function showResults(results, go_to_first, filterCrates) {
     }
     search.appendChild(resultsElem);
     // Reset focused elements.
+    // @ts-expect-error
     searchState.showResults(search);
+    // @ts-expect-error
     const elems = document.getElementById("search-tabs").childNodes;
+    // @ts-expect-error
     searchState.focusedByTab = [];
     let i = 0;
     for (const elem of elems) {
         const j = i;
+        // @ts-expect-error
         elem.onclick = () => printTab(j);
+        // @ts-expect-error
         searchState.focusedByTab.push(null);
         i += 1;
     }
     printTab(currentTab);
 }
 
+// @ts-expect-error
 function updateSearchHistory(url) {
     if (!browserSupportsHistoryApi()) {
         return;
     }
+    // @ts-expect-error
     const params = searchState.getQueryStringParams();
     if (!history.state && !params.search) {
         history.pushState(null, "", url);
@@ -4672,9 +5141,11 @@ function updateSearchHistory(url) {
  * @param {boolean} [forced]
  */
 async function search(forced) {
+    // @ts-expect-error
     const query = DocSearch.parseQuery(searchState.input.value.trim());
     let filterCrates = getFilterCrates();
 
+    // @ts-expect-error
     if (!forced && query.userQuery === currentResults) {
         if (query.userQuery.length > 0) {
             putBackSearch();
@@ -4682,8 +5153,10 @@ async function search(forced) {
         return;
     }
 
+    // @ts-expect-error
     searchState.setLoadingSearch();
 
+    // @ts-expect-error
     const params = searchState.getQueryStringParams();
 
     // In case we have no information about the saved crate and there is a URL query parameter,
@@ -4693,6 +5166,7 @@ async function search(forced) {
     }
 
     // Update document title to maintain a meaningful browser history
+    // @ts-expect-error
     searchState.title = "\"" + query.userQuery + "\" Search - Rust";
 
     // Because searching is incremental by character, only the most
@@ -4700,8 +5174,10 @@ async function search(forced) {
     updateSearchHistory(buildUrl(query.userQuery, filterCrates));
 
     await showResults(
+        // @ts-expect-error
         await docSearch.execQuery(query, filterCrates, window.currentCrate),
         params.go_to_first,
+        // @ts-expect-error
         filterCrates);
 }
 
@@ -4710,62 +5186,83 @@ async function search(forced) {
  * @param {Event} [e] - The event that triggered this call, if any
  */
 function onSearchSubmit(e) {
+    // @ts-expect-error
     e.preventDefault();
+    // @ts-expect-error
     searchState.clearInputTimeout();
     search();
 }
 
 function putBackSearch() {
+    // @ts-expect-error
     const search_input = searchState.input;
+    // @ts-expect-error
     if (!searchState.input) {
         return;
     }
+    // @ts-expect-error
     if (search_input.value !== "" && !searchState.isDisplayed()) {
+        // @ts-expect-error
         searchState.showResults();
         if (browserSupportsHistoryApi()) {
             history.replaceState(null, "",
                 buildUrl(search_input.value, getFilterCrates()));
         }
+        // @ts-expect-error
         document.title = searchState.title;
     }
 }
 
 function registerSearchEvents() {
+    // @ts-expect-error
     const params = searchState.getQueryStringParams();
 
     // Populate search bar with query string search term when provided,
     // but only if the input bar is empty. This avoid the obnoxious issue
     // where you start trying to do a search, and the index loads, and
     // suddenly your search is gone!
+    // @ts-expect-error
     if (searchState.input.value === "") {
+        // @ts-expect-error
         searchState.input.value = params.search || "";
     }
 
     const searchAfter500ms = () => {
+        // @ts-expect-error
         searchState.clearInputTimeout();
+        // @ts-expect-error
         if (searchState.input.value.length === 0) {
+            // @ts-expect-error
             searchState.hideResults();
         } else {
+            // @ts-expect-error
             searchState.timeout = setTimeout(search, 500);
         }
     };
+    // @ts-expect-error
     searchState.input.onkeyup = searchAfter500ms;
+    // @ts-expect-error
     searchState.input.oninput = searchAfter500ms;
+    // @ts-expect-error
     document.getElementsByClassName("search-form")[0].onsubmit = onSearchSubmit;
+    // @ts-expect-error
     searchState.input.onchange = e => {
         if (e.target !== document.activeElement) {
             // To prevent doing anything when it's from a blur event.
             return;
         }
         // Do NOT e.preventDefault() here. It will prevent pasting.
+        // @ts-expect-error
         searchState.clearInputTimeout();
         // zero-timeout necessary here because at the time of event handler execution the
         // pasted content is not in the input field yet. Shouldn’t make any difference for
         // change, though.
         setTimeout(search, 0);
     };
+    // @ts-expect-error
     searchState.input.onpaste = searchState.input.onchange;
 
+    // @ts-expect-error
     searchState.outputElement().addEventListener("keydown", e => {
         // We only handle unmodified keystrokes here. We don't want to interfere with,
         // for instance, alt-left and alt-right for history navigation.
@@ -4775,18 +5272,24 @@ function registerSearchEvents() {
         // up and down arrow select next/previous search result, or the
         // search box if we're already at the top.
         if (e.which === 38) { // up
+            // @ts-expect-error
             const previous = document.activeElement.previousElementSibling;
             if (previous) {
+                // @ts-expect-error
                 previous.focus();
             } else {
+                // @ts-expect-error
                 searchState.focus();
             }
             e.preventDefault();
         } else if (e.which === 40) { // down
+            // @ts-expect-error
             const next = document.activeElement.nextElementSibling;
             if (next) {
+                // @ts-expect-error
                 next.focus();
             }
+            // @ts-expect-error
             const rect = document.activeElement.getBoundingClientRect();
             if (window.innerHeight - rect.bottom < rect.height) {
                 window.scrollBy(0, rect.height);
@@ -4801,6 +5304,7 @@ function registerSearchEvents() {
         }
     });
 
+    // @ts-expect-error
     searchState.input.addEventListener("keydown", e => {
         if (e.which === 40) { // down
             focusSearchResult();
@@ -4808,11 +5312,14 @@ function registerSearchEvents() {
         }
     });
 
+    // @ts-expect-error
     searchState.input.addEventListener("focus", () => {
         putBackSearch();
     });
 
+    // @ts-expect-error
     searchState.input.addEventListener("blur", () => {
+        // @ts-expect-error
         searchState.input.placeholder = searchState.input.origPlaceholder;
     });
 
@@ -4823,6 +5330,7 @@ function registerSearchEvents() {
         const previousTitle = document.title;
 
         window.addEventListener("popstate", e => {
+            // @ts-expect-error
             const params = searchState.getQueryStringParams();
             // Revert to the previous title manually since the History
             // API ignores the title parameter.
@@ -4836,6 +5344,7 @@ function registerSearchEvents() {
             // nothing there, which lets you really go back to a
             // previous state with nothing in the bar.
             if (params.search && params.search.length > 0) {
+                // @ts-expect-error
                 searchState.input.value = params.search;
                 // Some browsers fire "onpopstate" for every page load
                 // (Chrome), while others fire the event only when actually
@@ -4845,9 +5354,11 @@ function registerSearchEvents() {
                 e.preventDefault();
                 search();
             } else {
+                // @ts-expect-error
                 searchState.input.value = "";
                 // When browsing back from search results the main page
                 // visibility must be reset.
+                // @ts-expect-error
                 searchState.hideResults();
             }
         });
@@ -4860,17 +5371,22 @@ function registerSearchEvents() {
     // that try to sync state between the URL and the search input. To work around it,
     // do a small amount of re-init on page show.
     window.onpageshow = () => {
+        // @ts-expect-error
         const qSearch = searchState.getQueryStringParams().search;
+        // @ts-expect-error
         if (searchState.input.value === "" && qSearch) {
+            // @ts-expect-error
             searchState.input.value = qSearch;
         }
         search();
     };
 }
 
+// @ts-expect-error
 function updateCrate(ev) {
     if (ev.target.value === "all crates") {
         // If we don't remove it from the URL, it'll be picked up again by the search.
+        // @ts-expect-error
         const query = searchState.input.value.trim();
         updateSearchHistory(buildUrl(query, null));
     }
@@ -4881,9 +5397,11 @@ function updateCrate(ev) {
     search(true);
 }
 
+// @ts-expect-error
 function initSearch(searchIndx) {
     rawSearchIndex = searchIndx;
     if (typeof window !== "undefined") {
+        // @ts-expect-error
         docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState);
         registerSearchEvents();
         // If there's a search term in the URL, execute the search now.
@@ -4891,6 +5409,7 @@ function initSearch(searchIndx) {
             search();
         }
     } else if (typeof exports !== "undefined") {
+        // @ts-expect-error
         docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState);
         exports.docSearch = docSearch;
         exports.parseQuery = DocSearch.parseQuery;
@@ -4902,8 +5421,11 @@ if (typeof exports !== "undefined") {
 }
 
 if (typeof window !== "undefined") {
+    // @ts-expect-error
     window.initSearch = initSearch;
+    // @ts-expect-error
     if (window.searchIndex !== undefined) {
+        // @ts-expect-error
         initSearch(window.searchIndex);
     }
 } else {
@@ -4918,19 +5440,23 @@ if (typeof window !== "undefined") {
 // https://fossies.org/linux/lucene/lucene/core/src/java/org/apache/lucene/util/automaton/
 //   LevenshteinAutomata.java
 class ParametricDescription {
+    // @ts-expect-error
     constructor(w, n, minErrors) {
         this.w = w;
         this.n = n;
         this.minErrors = minErrors;
     }
+    // @ts-expect-error
     isAccept(absState) {
         const state = Math.floor(absState / (this.w + 1));
         const offset = absState % (this.w + 1);
         return this.w - offset + this.minErrors[state] <= this.n;
     }
+    // @ts-expect-error
     getPosition(absState) {
         return absState % (this.w + 1);
     }
+    // @ts-expect-error
     getVector(name, charCode, pos, end) {
         let vector = 0;
         for (let i = pos; i < end; i += 1) {
@@ -4941,6 +5467,7 @@ class ParametricDescription {
         }
         return vector;
     }
+    // @ts-expect-error
     unpack(data, index, bitsPerValue) {
         const bitLoc = (bitsPerValue * index);
         const dataLoc = bitLoc >> 5;
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 183663b94fc..bf33e0f17e5 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -3,6 +3,9 @@
 /* global addClass, removeClass, onEach, onEachLazy */
 /* global MAIN_ID, getVar, getSettingsButton, getHelpButton */
 
+// Eventually fix this.
+// @ts-nocheck
+
 "use strict";
 
 (function() {
@@ -50,6 +53,12 @@
                     removeClass(document.documentElement, "hide-modnav");
                 }
                 break;
+            case "sans-serif-fonts":
+                if (value === true) {
+                    addClass(document.documentElement, "sans-serif");
+                } else {
+                    removeClass(document.documentElement, "sans-serif");
+                }
         }
     }
 
@@ -232,6 +241,11 @@
                 "js_name": "disable-shortcuts",
                 "default": false,
             },
+            {
+                "name": "Use sans serif fonts",
+                "js_name": "sans-serif-fonts",
+                "default": false,
+            },
         ];
 
         // Then we build the DOM.
diff --git a/src/librustdoc/html/static/js/src-script.js b/src/librustdoc/html/static/js/src-script.js
index 3003f4c1503..8f712f4c20c 100644
--- a/src/librustdoc/html/static/js/src-script.js
+++ b/src/librustdoc/html/static/js/src-script.js
@@ -5,6 +5,9 @@
 /* global addClass, onEachLazy, removeClass, browserSupportsHistoryApi */
 /* global updateLocalStorage, getVar */
 
+// Eventually fix this.
+// @ts-nocheck
+
 "use strict";
 
 (function() {
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index d77804d045e..10369e77320 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -5,15 +5,28 @@
 // the page, so we don't see major layout changes during the load of the page.
 "use strict";
 
+/**
+ * @import * as rustdoc from "./rustdoc.d.ts";
+ */
+
 const builtinThemes = ["light", "dark", "ayu"];
 const darkThemes = ["dark", "ayu"];
-window.currentTheme = document.getElementById("themeStyle");
+window.currentTheme = (function() {
+    const currentTheme = document.getElementById("themeStyle");
+    return currentTheme instanceof HTMLLinkElement ? currentTheme : null;
+})();
 
 const settingsDataset = (function() {
     const settingsElement = document.getElementById("default-settings");
     return settingsElement && settingsElement.dataset ? settingsElement.dataset : null;
 })();
 
+/**
+ * Get a configuration value. If it's not set, get the default.
+ *
+ * @param {string} settingName
+ * @returns
+ */
 function getSettingValue(settingName) {
     const current = getCurrentValue(settingName);
     if (current === null && settingsDataset !== null) {
@@ -29,17 +42,39 @@ function getSettingValue(settingName) {
 
 const localStoredTheme = getSettingValue("theme");
 
+/**
+ * Check if a DOM Element has the given class set.
+ * If `elem` is null, returns false.
+ *
+ * @param {HTMLElement|null} elem
+ * @param {string} className
+ * @returns {boolean}
+ */
 // eslint-disable-next-line no-unused-vars
 function hasClass(elem, className) {
-    return elem && elem.classList && elem.classList.contains(className);
+    return !!elem && !!elem.classList && elem.classList.contains(className);
 }
 
+/**
+ * Add a class to a DOM Element. If `elem` is null,
+ * does nothing. This function is idempotent.
+ *
+ * @param {HTMLElement|null} elem
+ * @param {string} className
+ */
 function addClass(elem, className) {
     if (elem && elem.classList) {
         elem.classList.add(className);
     }
 }
 
+/**
+ * Remove a class from a DOM Element. If `elem` is null,
+ * does nothing. This function is idempotent.
+ *
+ * @param {HTMLElement|null} elem
+ * @param {string} className
+ */
 // eslint-disable-next-line no-unused-vars
 function removeClass(elem, className) {
     if (elem && elem.classList) {
@@ -49,8 +84,8 @@ function removeClass(elem, className) {
 
 /**
  * Run a callback for every element of an Array.
- * @param {Array<?>}    arr        - The array to iterate over
- * @param {function(?)} func       - The callback
+ * @param {Array<?>}                       arr  - The array to iterate over
+ * @param {function(?): boolean|undefined} func - The callback
  */
 function onEach(arr, func) {
     for (const elem of arr) {
@@ -67,8 +102,8 @@ function onEach(arr, func) {
  * or a "live" NodeList while modifying it can be very slow.
  * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
  * https://developer.mozilla.org/en-US/docs/Web/API/NodeList
- * @param {NodeList<?>|HTMLCollection<?>} lazyArray  - An array to iterate over
- * @param {function(?)}                   func       - The callback
+ * @param {NodeList|HTMLCollection} lazyArray  - An array to iterate over
+ * @param {function(?): boolean}    func       - The callback
  */
 // eslint-disable-next-line no-unused-vars
 function onEachLazy(lazyArray, func) {
@@ -77,6 +112,15 @@ function onEachLazy(lazyArray, func) {
         func);
 }
 
+/**
+ * Set a configuration value. This uses localstorage,
+ * with a `rustdoc-` prefix, to avoid clashing with other
+ * web apps that may be running in the same domain (for example, mdBook).
+ * If localStorage is disabled, this function does nothing.
+ *
+ * @param {string} name
+ * @param {string} value
+ */
 function updateLocalStorage(name, value) {
     try {
         window.localStorage.setItem("rustdoc-" + name, value);
@@ -85,6 +129,15 @@ function updateLocalStorage(name, value) {
     }
 }
 
+/**
+ * Get a configuration value. If localStorage is disabled,
+ * this function returns null. If the setting was never
+ * changed by the user, it also returns null; if you want to
+ * be able to use a default value, call `getSettingValue` instead.
+ *
+ * @param {string} name
+ * @returns {string|null}
+ */
 function getCurrentValue(name) {
     try {
         return window.localStorage.getItem("rustdoc-" + name);
@@ -93,19 +146,29 @@ function getCurrentValue(name) {
     }
 }
 
-// Get a value from the rustdoc-vars div, which is used to convey data from
-// Rust to the JS. If there is no such element, return null.
-const getVar = (function getVar(name) {
+/**
+ * Get a value from the rustdoc-vars div, which is used to convey data from
+ * Rust to the JS. If there is no such element, return null.
+ *
+ * @param {string} name
+ * @returns {string|null}
+ */
+function getVar(name) {
     const el = document.querySelector("head > meta[name='rustdoc-vars']");
-    return el ? el.attributes["data-" + name].value : null;
-});
+    return el ? el.getAttribute("data-" + name) : null;
+}
 
+/**
+ * Change the current theme.
+ * @param {string|null} newThemeName
+ * @param {boolean} saveTheme
+ */
 function switchTheme(newThemeName, saveTheme) {
-    const themeNames = getVar("themes").split(",").filter(t => t);
+    const themeNames = (getVar("themes") || "").split(",").filter(t => t);
     themeNames.push(...builtinThemes);
 
     // Ensure that the new theme name is among the defined themes
-    if (themeNames.indexOf(newThemeName) === -1) {
+    if (newThemeName === null || themeNames.indexOf(newThemeName) === -1) {
         return;
     }
 
@@ -118,7 +181,7 @@ function switchTheme(newThemeName, saveTheme) {
     document.documentElement.setAttribute("data-theme", newThemeName);
 
     if (builtinThemes.indexOf(newThemeName) !== -1) {
-        if (window.currentTheme) {
+        if (window.currentTheme && window.currentTheme.parentNode) {
             window.currentTheme.parentNode.removeChild(window.currentTheme);
             window.currentTheme = null;
         }
@@ -130,7 +193,10 @@ function switchTheme(newThemeName, saveTheme) {
             // rendering, but if we are done, it would blank the page.
             if (document.readyState === "loading") {
                 document.write(`<link rel="stylesheet" id="themeStyle" href="${newHref}">`);
-                window.currentTheme = document.getElementById("themeStyle");
+                window.currentTheme = (function() {
+                    const currentTheme = document.getElementById("themeStyle");
+                    return currentTheme instanceof HTMLLinkElement ? currentTheme : null;
+                })();
             } else {
                 window.currentTheme = document.createElement("link");
                 window.currentTheme.rel = "stylesheet";
@@ -179,11 +245,13 @@ const updateTheme = (function() {
     return updateTheme;
 })();
 
+// @ts-ignore
 if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
     // update the preferred dark theme if the user is already using a dark theme
     // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732
     if (getSettingValue("use-system-theme") === null
         && getSettingValue("preferred-dark-theme") === null
+        && localStoredTheme !== null
         && darkThemes.indexOf(localStoredTheme) >= 0) {
         updateLocalStorage("preferred-dark-theme", localStoredTheme);
     }
@@ -211,6 +279,9 @@ if (getSettingValue("hide-toc") === "true") {
 if (getSettingValue("hide-modnav") === "true") {
     addClass(document.documentElement, "hide-modnav");
 }
+if (getSettingValue("sans-serif-fonts") === "true") {
+    addClass(document.documentElement, "sans-serif");
+}
 function updateSidebarWidth() {
     const desktopSidebarWidth = getSettingValue("desktop-sidebar-width");
     if (desktopSidebarWidth && desktopSidebarWidth !== "null") {
diff --git a/src/librustdoc/html/static/js/tsconfig.json b/src/librustdoc/html/static/js/tsconfig.json
new file mode 100644
index 00000000000..b81099bb9df
--- /dev/null
+++ b/src/librustdoc/html/static/js/tsconfig.json
@@ -0,0 +1,15 @@
+{
+  "compilerOptions": {
+    "target": "es2023",
+    "module": "esnext",
+    "rootDir": "./",
+    "allowJs": true,
+    "checkJs": true,
+    "noEmit": true,
+    "strict": true,
+    "skipLibCheck": true
+  },
+  "typeAcquisition": {
+    "include": ["./rustdoc.d.ts"]
+  }
+}
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 6457ac731cb..0bcaf11da0c 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -98,10 +98,15 @@ static_files! {
     rust_logo_svg => "static/images/rust-logo.svg",
     rust_favicon_svg => "static/images/favicon.svg",
     rust_favicon_png_32 => "static/images/favicon-32x32.png",
+    fira_sans_italic => "static/fonts/FiraSans-Italic.woff2",
     fira_sans_regular => "static/fonts/FiraSans-Regular.woff2",
     fira_sans_medium => "static/fonts/FiraSans-Medium.woff2",
+    fira_sans_medium_italic => "static/fonts/FiraSans-MediumItalic.woff2",
+    fira_mono_regular => "static/fonts/FiraMono-Regular.woff2",
+    fira_mono_medium => "static/fonts/FiraMono-Medium.woff2",
     fira_sans_license => "static/fonts/FiraSans-LICENSE.txt",
     source_serif_4_regular => "static/fonts/SourceSerif4-Regular.ttf.woff2",
+    source_serif_4_semibold => "static/fonts/SourceSerif4-Semibold.ttf.woff2",
     source_serif_4_bold => "static/fonts/SourceSerif4-Bold.ttf.woff2",
     source_serif_4_italic => "static/fonts/SourceSerif4-It.ttf.woff2",
     source_serif_4_license => "static/fonts/SourceSerif4-LICENSE.md",
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index a05d6ca8313..5ef376f4acb 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -7,7 +7,7 @@
     <meta name="description" content="{{page.description}}"> {# #}
     <title>{{page.title}}</title> {# #}
     <script>if(window.location.protocol!=="file:") {# Hack to skip preloading fonts locally - see #98769 #}
-    document.head.insertAdjacentHTML("beforeend","{{files.source_serif_4_regular}},{{files.fira_sans_regular}},{{files.fira_sans_medium}},{{files.source_code_pro_regular}},{{files.source_code_pro_semibold}}".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}${f}">`).join("")) {# #}
+    document.head.insertAdjacentHTML("beforeend","{{files.source_serif_4_regular}},{{files.fira_sans_italic}},{{files.fira_sans_regular}},{{files.fira_sans_medium_italic}},{{files.fira_sans_medium}},{{files.source_code_pro_regular}},{{files.source_code_pro_semibold}}".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}${f}">`).join("")) {# #}
     </script> {# #}
     <link rel="stylesheet" {#+ #}
           href="{{static_root_path|safe}}{{files.normalize_css}}"> {# #}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index bb954a31891..af225c9d68d 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -177,9 +177,8 @@ pub fn main() {
     rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG"));
 
     let exit_code = rustc_driver::catch_with_exit_code(|| {
-        let at_args = rustc_driver::args::raw_args(&early_dcx)?;
+        let at_args = rustc_driver::args::raw_args(&early_dcx);
         main_args(&mut early_dcx, &at_args);
-        Ok(())
     });
     process::exit(exit_code);
 }
@@ -814,7 +813,12 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
         }
     };
 
-    match (options.should_test, config::markdown_input(&input)) {
+    let output_format = options.output_format;
+
+    match (
+        options.should_test || output_format == config::OutputFormat::Doctest,
+        config::markdown_input(&input),
+    ) {
         (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)),
         (true, None) => return doctest::run(dcx, input, options),
         (false, Some(md_input)) => {
@@ -849,7 +853,6 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
     // plug/cleaning passes.
     let crate_version = options.crate_version.clone();
 
-    let output_format = options.output_format;
     let scrape_examples_options = options.scrape_examples_options.clone();
     let bin_crate = options.bin_crate;
 
@@ -899,6 +902,8 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
                 config::OutputFormat::Json => sess.time("render_json", || {
                     run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx)
                 }),
+                // Already handled above with doctest runners.
+                config::OutputFormat::Doctest => unreachable!(),
             }
         })
     })
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject cecde95c119a456c30e57d3e4b31fff5a7d83df
+Subproject 0e3d73849ab8cbbab3ec5c65cbd555586cb2133
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index c26ad319f4f..48506127dee 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -788,7 +788,7 @@ don't hesitate to ask on [Zulip] or in the issue/PR.
 [`snippet`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/source/fn.snippet.html
 [let-chains]: https://github.com/rust-lang/rust/pull/94927
 [from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
-[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
+[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.in_external_macro
 [span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
 [applicability]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html
 [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
index b44ad80a25c..051febc2ca5 100644
--- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md
+++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
@@ -218,7 +218,7 @@ functions to deal with macros:
   > context. And so just using `span.from_expansion()` is often good enough.
 
 
-- `in_external_macro(span)`: detect if the given span is from a macro defined in
+- `span.in_external_macro(sm)`: detect if the given span is from a macro defined in
   a foreign crate. If you want the lint to work with macro-generated code, this
   is the next line of defense to avoid macros not defined in the current crate.
   It doesn't make sense to lint code that the coder can't change.
@@ -227,15 +227,13 @@ functions to deal with macros:
   crates
 
   ```rust
-  use rustc_middle::lint::in_external_macro;
-
   use a_crate_with_macros::foo;
 
   // `foo` is defined in `a_crate_with_macros`
   foo!("bar");
 
   // if we lint the `match` of `foo` call and test its span
-  assert_eq!(in_external_macro(cx.sess(), match_span), true);
+  assert_eq!(match_span.in_external_macro(cx.sess().source_map()), true);
   ```
 
 - `span.ctxt()`: the span's context represents whether it is from expansion, and
diff --git a/src/tools/clippy/book/src/development/macro_expansions.md b/src/tools/clippy/book/src/development/macro_expansions.md
index 125b6c4bc5b..36092f82e26 100644
--- a/src/tools/clippy/book/src/development/macro_expansions.md
+++ b/src/tools/clippy/book/src/development/macro_expansions.md
@@ -120,7 +120,7 @@ assert_ne!(x_is_some_span.ctxt(), x_unwrap_span.ctxt());
 
 ### The `in_external_macro` function
 
-`rustc_middle::lint` provides a function ([`in_external_macro`]) that can
+`Span` provides a method ([`in_external_macro`]) that can
 detect if the given span is from a macro defined in a foreign crate.
 
 Therefore, if we really want a new lint to work with macro-generated code,
@@ -144,7 +144,7 @@ Also assume that we get the corresponding variable `foo_span` for the
 results in `true` (note that `cx` can be `EarlyContext` or `LateContext`):
 
 ```rust
-if in_external_macro(cx.sess(), foo_span) {
+if foo_span.in_external_macro(cx.sess().source_map()) {
     // We should ignore macro from a foreign crate.
     return;
 }
@@ -153,6 +153,6 @@ if in_external_macro(cx.sess(), foo_span) {
 [`ctxt`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.ctxt
 [expansion]: https://rustc-dev-guide.rust-lang.org/macro-expansion.html#expansion-and-ast-integration
 [`from_expansion`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
-[`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
+[`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.in_external_macro
 [Span]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html
 [SyntaxContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
index 2af5178920d..0f7f779e8ea 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
@@ -5,7 +5,6 @@ use clippy_utils::source::{trim_span, walk_span_to_context};
 use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -45,7 +44,7 @@ impl EarlyLintPass for AlmostCompleteRange {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
         if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind
             && is_incomplete_range(start, end)
-            && !in_external_macro(cx.sess(), e.span)
+            && !e.span.in_external_macro(cx.sess().source_map())
         {
             span_lint_and_then(
                 cx,
@@ -74,7 +73,7 @@ impl EarlyLintPass for AlmostCompleteRange {
         if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
             && matches!(kind.node, RangeEnd::Excluded)
             && is_incomplete_range(start, end)
-            && !in_external_macro(cx.sess(), p.span)
+            && !p.span.in_external_macro(cx.sess().source_map())
         {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 0389223c3e0..f519a65fc27 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -9,7 +9,6 @@ use rustc_hir::{
     Variant, VariantData,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -248,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
             ItemKind::Enum(enum_def, _generics) if self.enable_ordering_for_enum => {
                 let mut cur_v: Option<&Variant<'_>> = None;
                 for variant in enum_def.variants {
-                    if in_external_macro(cx.sess(), variant.span) {
+                    if variant.span.in_external_macro(cx.sess().source_map()) {
                         continue;
                     }
 
@@ -263,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
             ItemKind::Struct(VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => {
                 let mut cur_f: Option<&FieldDef<'_>> = None;
                 for field in *fields {
-                    if in_external_macro(cx.sess(), field.span) {
+                    if field.span.in_external_macro(cx.sess().source_map()) {
                         continue;
                     }
 
@@ -281,7 +280,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
                 let mut cur_t: Option<&TraitItemRef> = None;
 
                 for item in *item_ref {
-                    if in_external_macro(cx.sess(), item.span) {
+                    if item.span.in_external_macro(cx.sess().source_map()) {
                         continue;
                     }
 
@@ -304,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
                 let mut cur_t: Option<&ImplItemRef> = None;
 
                 for item in trait_impl.items {
-                    if in_external_macro(cx.sess(), item.span) {
+                    if item.span.in_external_macro(cx.sess().source_map()) {
                         continue;
                     }
 
@@ -348,7 +347,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
         // as no sorting by source map/line of code has to be applied.
         //
         for item in items {
-            if in_external_macro(cx.sess(), item.span) {
+            if item.span.in_external_macro(cx.sess().source_map()) {
                 continue;
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs
index fefd8195f8e..847653ed6e9 100644
--- a/src/tools/clippy/clippy_lints/src/as_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -49,7 +48,7 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
 impl<'tcx> LateLintPass<'tcx> for AsConversions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         if let ExprKind::Cast(_, _) = expr.kind
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, expr)
         {
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
index 1879391ec29..53d9725703c 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs
@@ -4,11 +4,10 @@ use clippy_utils::is_from_proc_macro;
 use rustc_ast::{AttrStyle, Attribute};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 
 // Separate each crate's features.
 pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) {
-    if !in_external_macro(cx.sess(), attr.span)
+    if !attr.span.in_external_macro(cx.sess().source_map())
         && let AttrStyle::Outer = attr.style
         && let Some(ident) = attr.ident()
         && !is_from_proc_macro(cx, attr)
diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
index 788377fe83c..5bf077990e1 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_ast::{MetaItemInner, MetaItemKind};
 use rustc_lint::{EarlyContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 
@@ -17,7 +16,7 @@ pub(super) fn check<'cx>(cx: &EarlyContext<'cx>, name: Symbol, items: &[MetaItem
     }
 
     // Check if the attribute is in an external macro and therefore out of the developer's control
-    if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, attr) {
+    if attr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, attr) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index e7158a6a6b6..e3e081ce08e 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -5,14 +5,13 @@ use clippy_utils::source::{SpanRangeExt, first_line_of_span};
 use rustc_ast::{Attribute, Item, ItemKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::sym;
 
 pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
     let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use));
 
     for attr in attrs {
-        if in_external_macro(cx.sess(), attr.span) {
+        if attr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         if let Some(lint_list) = &attr.meta_item_list() {
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
index eb05dc96cde..aab0af0d743 100644
--- a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
+++ b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
@@ -4,7 +4,6 @@ use clippy_utils::{higher, is_from_proc_macro};
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -54,7 +53,7 @@ const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression conditio
 
 impl<'tcx> LateLintPass<'tcx> for BlocksInConditions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 79fd6ffe46c..3b861848f94 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -7,7 +7,6 @@ use rustc_hir::def::Res;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LetStmt, Node, QPath, Ty, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::{Span, sym};
 
@@ -50,7 +49,7 @@ impl LateLintPass<'_> for BoxDefault {
             // This is the `T::default()` (or default equivalent) of `Box::new(T::default())`
             && let ExprKind::Call(arg_path, _) = arg.kind
             // And we are not in a foreign crate's macro
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             // And the argument expression has the same context as the outer call expression
             // or that we are inside a `vec!` macro expansion
             && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr))
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index d90cf124fe4..521bd394901 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -29,7 +29,6 @@ use clippy_utils::is_hir_ty_cfg_dependant;
 use clippy_utils::msrvs::{self, Msrv};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -796,7 +795,7 @@ impl_lint_pass!(Casts => [
 
 impl<'tcx> LateLintPass<'tcx> for Casts {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 9e1876e40f9..7885f171461 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -8,7 +8,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
 use std::ops::ControlFlow;
 
@@ -142,7 +141,7 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
+    if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) {
         if let Some(id) = path_to_local(cast_expr)
             && !cx.tcx.hir().span(id).eq_ctxt(cast_expr.span)
         {
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 1edfde97422..9516af7334d 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -6,7 +6,6 @@ use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -64,7 +63,7 @@ impl LateLintPass<'_> for CheckedConversions {
                 },
                 _ => return,
             }
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && !is_in_const_context(cx)
             && self.msrv.meets(msrvs::TRY_FROM)
             && let Some(cv) = match op2 {
diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs
index 589b99518a0..7bae04a10f1 100644
--- a/src/tools/clippy/clippy_lints/src/ctfe.rs
+++ b/src/tools/clippy/clippy_lints/src/ctfe.rs
@@ -21,6 +21,6 @@ impl<'tcx> LateLintPass<'tcx> for ClippyCtfe {
         _: Span,
         defid: LocalDefId,
     ) {
-        cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint
+        cx.tcx.ensure_ok().mir_drops_elaborated_and_const_checked(defid); // Lint
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index a96c86f0765..06376c57119 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -7,7 +7,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, SyntaxContext, sym};
 
@@ -60,7 +59,7 @@ impl LateLintPass<'_> for DbgMacro {
 
         if cur_syntax_ctxt != self.prev_ctxt &&
             let Some(macro_call) = first_dbg_macro_in_expansion(cx, expr.span) &&
-            !in_external_macro(cx.sess(), macro_call.span) &&
+            !macro_call.span.in_external_macro(cx.sess().source_map()) &&
             self.checked_dbg_call_site.insert(macro_call.span) &&
             // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
             !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id))
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index ca3eaae7b85..772268e7899 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -9,7 +9,6 @@ use rustc_hir::{
     StructTailExpr,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
 use rustc_session::declare_lint_pass;
 use std::iter;
@@ -86,7 +85,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
 
     /// Check whether a passed literal has potential to cause fallback or not.
     fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
-        if !in_external_macro(self.cx.sess(), lit.span)
+        if !lit.span.in_external_macro(self.cx.sess().source_map())
             && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)))
             && matches!(
                 lit.node,
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 15530c3dbc5..3d8ce7becdb 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -22,7 +22,6 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_resolve::rustdoc::{
     DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range,
@@ -675,7 +674,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
                 match item.kind {
                     ItemKind::Fn { sig, body: body_id, .. } => {
                         if !(is_entrypoint_fn(cx, item.owner_id.to_def_id())
-                            || in_external_macro(cx.tcx.sess, item.span))
+                            || item.span.in_external_macro(cx.tcx.sess.source_map()))
                         {
                             let body = cx.tcx.hir().body(body_id);
 
@@ -711,7 +710,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
             },
             Node::TraitItem(trait_item) => {
                 if let TraitItemKind::Fn(sig, ..) = trait_item.kind
-                    && !in_external_macro(cx.tcx.sess, trait_item.span)
+                    && !trait_item.span.in_external_macro(cx.tcx.sess.source_map())
                 {
                     missing_headers::check(
                         cx,
@@ -726,7 +725,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
             },
             Node::ImplItem(impl_item) => {
                 if let ImplItemKind::Fn(sig, body_id) = impl_item.kind
-                    && !in_external_macro(cx.tcx.sess, impl_item.span)
+                    && !impl_item.span.in_external_macro(cx.tcx.sess.source_map())
                     && !is_trait_impl_item(cx, impl_item.hir_id())
                 {
                     let body = cx.tcx.hir().body(body_id);
@@ -791,7 +790,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
 
     let (fragments, _) = attrs_to_doc_fragments(
         attrs.iter().filter_map(|attr| {
-            if in_external_macro(cx.sess(), attr.span) {
+            if attr.span.in_external_macro(cx.sess().source_map()) {
                 None
             } else {
                 Some((attr, None))
diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
index 5315f55ba38..a38e853172f 100644
--- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
+++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -50,7 +49,7 @@ impl EarlyLintPass for ElseIfWithoutElse {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
         if let ExprKind::If(_, _, Some(ref els)) = item.kind
             && let ExprKind::If(_, _, None) = els.kind
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
         {
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index 209104c5385..29deaaf3bc7 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::Symbol;
@@ -119,7 +118,7 @@ impl LateLintPass<'_> for EndianBytes {
             },
             _ => return,
         };
-        if !in_external_macro(cx.sess(), expr.span)
+        if !expr.span.in_external_macro(cx.sess().source_map())
             && let ty = cx.typeck_results().expr_ty(ty_expr)
             && ty.is_primitive_ty()
         {
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 8a5cf7f56d5..cd9ab2764ac 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -4,7 +4,6 @@ use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
 
@@ -56,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
         PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
         PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
-        PatKind::Path(_) | PatKind::Expr(_) => true,
+        PatKind::Expr(_) => true,
     }
 }
 
@@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Let(let_expr) = expr.kind
             && unary_pattern(let_expr.pat)
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
             let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
index dfea40db182..36567b3ded0 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
@@ -5,7 +5,6 @@ use rustc_ast::node_id::NodeSet;
 use rustc_ast::visit::{Visitor, walk_block, walk_item};
 use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -125,7 +124,7 @@ struct NestingVisitor<'conf, 'cx> {
 
 impl NestingVisitor<'_, '_> {
     fn check_indent(&mut self, span: Span, id: NodeId) -> bool {
-        if self.nest_level > self.conf.excessive_nesting_threshold && !in_external_macro(self.cx.sess(), span) {
+        if self.nest_level > self.conf.excessive_nesting_threshold && !span.in_external_macro(self.cx.sess().source_map()) {
             self.conf.nodes.insert(id);
 
             return true;
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index cdbfe7af8f9..5d93aceb33f 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -10,7 +10,6 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -261,7 +260,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
             && !generics.params.is_empty()
             && !is_empty_body(cx, body_id)
             && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, item)
         {
             let mut walker = TypeWalker::new(cx, generics);
@@ -277,7 +276,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
             && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
             && !is_empty_body(cx, body_id)
             && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, item)
         {
             let mut walker = TypeWalker::new(cx, item.generics);
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index 34e93bdb9b9..c8fe7ac73cb 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -3,7 +3,6 @@ use clippy_utils::is_span_if;
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 
@@ -202,7 +201,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
     if let ExprKind::If(_, then, Some(else_)) = &expr.kind
         && (is_block(else_) || is_if(else_))
         && !then.span.from_expansion() && !else_.span.from_expansion()
-        && !in_external_macro(cx.sess(), expr.span)
+        && !expr.span.in_external_macro(cx.sess().source_map())
 
         // workaround for rust-lang/rust#43081
         && expr.span.lo().0 != 0 && expr.span.hi().0 != 0
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 90d3db2700f..e480805cac2 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -5,7 +5,6 @@ use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{self as hir, Attribute, QPath};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{Span, sym};
 
@@ -107,7 +106,7 @@ fn check_needless_must_use(
     attrs: &[Attribute],
     sig: &FnSig<'_>,
 ) {
-    if in_external_macro(cx.sess(), item_span) {
+    if item_span.in_external_macro(cx.sess().source_map()) {
         return;
     }
     if returns_unit(decl) {
@@ -185,7 +184,7 @@ fn check_must_use_candidate<'tcx>(
 ) {
     if has_mutable_arg(cx, body)
         || mutates_static(cx, body)
-        || in_external_macro(cx.sess(), item_span)
+        || item_span.in_external_macro(cx.sess().source_map())
         || returns_unit(decl)
         || !cx.effective_visibilities.is_exported(item_id.def_id)
         || is_must_use_ty(cx, return_ty(cx, item_id))
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 9c396986f62..74d365a7255 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -2,7 +2,6 @@ use clippy_utils::msrvs::{self, Msrv};
 use rustc_errors::Diag;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{Span, sym};
 
@@ -20,7 +19,7 @@ fn result_err_ty<'tcx>(
     id: hir::def_id::LocalDefId,
     item_span: Span,
 ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
-    if !in_external_macro(cx.sess(), item_span)
+    if !item_span.in_external_macro(cx.sess().source_map())
         && let hir::FnRetTy::Return(hir_ty) = decl.output
         && let ty = cx
             .tcx
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
index 0f5ce340c44..4f90d9655b4 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -3,7 +3,6 @@ use clippy_utils::source::SpanRangeExt;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::Span;
 
 use super::TOO_MANY_LINES;
@@ -17,7 +16,7 @@ pub(super) fn check_fn(
 ) {
     // Closures must be contained in a parent body, which will be checked for `too_many_lines`.
     // Don't check closures for `too_many_lines` to avoid duplicated lints.
-    if matches!(kind, FnKind::Closure) || in_external_macro(cx.sess(), span) {
+    if matches!(kind, FnKind::Closure) || span.in_external_macro(cx.sess().source_map()) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index 3fc0a696522..51e2944e6f9 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -11,7 +11,6 @@ use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
             && !is_else_clause(cx.tcx, expr)
             && !is_in_const_context(cx)
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && self.msrv.meets(msrvs::BOOL_THEN)
             && !contains_return(then_block.stmts)
         {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index ba06567b957..5f95464e4d4 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, SyntaxContext};
@@ -227,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
     ) {
         if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_)))
             || !span.eq_ctxt(body.value.span)
-            || in_external_macro(cx.sess(), span)
+            || span.in_external_macro(cx.sess().source_map())
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index 4f066113aea..f5ad79a0027 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_hir;
 use rustc_hir::{Block, ItemKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -70,7 +69,7 @@ impl LateLintPass<'_> for ItemsAfterStatements {
                 // Don't use `next` due to the complex filter chain.
                 .for_each(|item| {
                     // Only do the macro check once, but delay it until it's needed.
-                    if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) {
+                    if !*in_external.get_or_insert_with(|| block.span.in_external_macro(cx.sess().source_map())) {
                         span_lint_hir(
                             cx,
                             ITEMS_AFTER_STATEMENTS,
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 906da81b183..238f66d6675 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -6,7 +6,6 @@ use rustc_ast::Mutability;
 use rustc_errors::Applicability;
 use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -131,7 +130,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
             && trait_ref
                 .trait_def_id()
                 .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
             && let expected_method_name = match mtbl {
                 Mutability::Mut => sym::iter_mut,
@@ -193,7 +192,7 @@ impl {self_ty_without_ref} {{
             _ => return,
         };
 
-        if !in_external_macro(cx.sess(), item.span)
+        if !item.span.in_external_macro(cx.sess().source_map())
             && let ImplItemKind::Fn(sig, _) = item.kind
             && let FnRetTy::Return(ret) = sig.decl.output
             && is_nameable_in_impl_trait(ret)
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 623b6b4fcc1..cabf10b7e0e 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -56,9 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
             && !item.span.from_expansion()
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Array(element_type, cst) = ty.kind()
-            && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx
-                .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_valtree()
-            && let element_count = element_count.to_target_usize(cx.tcx)
+            && let Some(element_count) = cx.tcx
+                .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_target_usize(cx.tcx)
             && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
             && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
         {
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index 923089c7223..d9953dbc261 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -5,7 +5,6 @@ use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -78,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Adt(adt, subst) = ty.kind()
             && adt.variants().len() > 1
-            && !in_external_macro(cx.tcx.sess, item.span)
+            && !item.span.in_external_macro(cx.tcx.sess.source_map())
         {
             let variants_size = AdtVariantInfo::new(cx, *adt, subst);
 
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index 46d7df6995a..6f5c5d6b3ea 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -8,7 +8,7 @@ use clippy_utils::source::snippet;
 use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, ConstKind};
+use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, sym};
 
@@ -81,8 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
             && let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind
             && !self.is_from_vec_macro(cx, expr.span)
             && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
-            && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
-            && let element_count = element_count.to_target_usize(cx.tcx)
+            && let Some(element_count) = cst.try_to_target_usize(cx.tcx)
             && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
             && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| {
                 matches!(
diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
index fb46bdcab6e..6f2ce04e8f8 100644
--- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
 use rustc_span::{Symbol, sym};
@@ -54,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
         // so lint on the `use` statement directly.
         if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
             && self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && let Some(def_id) = path.res[0].opt_def_id()
         {
             let module = if is_integer_module(cx, def_id) {
@@ -139,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
         };
 
         if self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, expr)
         {
             span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index b522c22a44d..bdbf5b37c5f 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -3,7 +3,6 @@ use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
 use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
 use rustc_hir::{LetStmt, LocalSource, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{GenericArgKind, IsSuggestable};
 use rustc_session::declare_lint_pass;
 use rustc_span::{BytePos, Span};
@@ -141,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
         if matches!(local.source, LocalSource::Normal)
             && let PatKind::Wild = local.pat.kind
             && let Some(init) = local.init
-            && !in_external_macro(cx.tcx.sess, local.span)
+            && !local.span.in_external_macro(cx.tcx.sess.source_map())
         {
             let init_ty = cx.typeck_results().expr_ty(init);
             let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 34ded6c6500..9c8488ff381 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_from_proc_macro;
 use rustc_hir::{LetStmt, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -30,7 +29,7 @@ impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
         if let Some(ty) = local.ty // Ensure that it has a type defined
             && let TyKind::Infer(()) = &ty.kind // that type is '_'
             && local.span.eq_ctxt(ty.span)
-            && !in_external_macro(cx.tcx.sess, local.span)
+            && !local.span.in_external_macro(cx.tcx.sess.source_map())
             && !is_from_proc_macro(cx, ty)
         {
             span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index c9ab0beb5df..860c0584acc 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -21,7 +21,6 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter as middle_nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
@@ -164,7 +163,7 @@ fn check_fn_inner<'tcx>(
     report_extra_lifetimes: bool,
     msrv: &Msrv,
 ) {
-    if in_external_macro(cx.sess(), span) || has_where_lifetimes(cx, generics) {
+    if span.in_external_macro(cx.sess().source_map()) || has_where_lifetimes(cx, generics) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index a4cedf3bed3..805de23408b 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -6,7 +6,6 @@ use rustc_ast::ast::{Expr, ExprKind, LitKind};
 use rustc_ast::token;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use std::iter;
@@ -207,7 +206,7 @@ impl_lint_pass!(LiteralDigitGrouping => [
 impl EarlyLintPass for LiteralDigitGrouping {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::Lit(lit) = expr.kind
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             self.check_lit(cx, lit, expr.span);
         }
@@ -421,7 +420,7 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]
 impl EarlyLintPass for DecimalLiteralRepresentation {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::Lit(lit) = expr.kind
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             self.check_lit(cx, lit, expr.span);
         }
diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
index 6be30f3c957..4d206850c99 100644
--- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
@@ -6,7 +6,6 @@ use rustc_ast::Label;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::sym;
 
 use super::INFINITE_LOOP;
@@ -30,7 +29,7 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) {
+    if expr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, expr) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index a1951b9da44..052e6502da9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -9,7 +9,6 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BinOpKind, Constness, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 
@@ -142,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
             // 16 possible alignments of constants/operands. For now, let's use `partition`.
             && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
             && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && (
                 is_not_const(cx.tcx, cx.tcx.hir().enclosing_body_owner(expr.hir_id).into())
                     || self.msrv.meets(msrvs::CONST_FLOAT_CLASSIFY)
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 8503dde3fb6..3643b8c4425 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -7,9 +7,8 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_lint_allowed, is_never_expr, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
@@ -55,7 +54,7 @@ impl<'tcx> QuestionMark {
             && init.span.eq_ctxt(stmt.span)
             && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
             && self.msrv.meets(msrvs::LET_ELSE)
-            && !in_external_macro(cx.sess(), stmt.span)
+            && !stmt.span.in_external_macro(cx.sess().source_map())
         {
             match if_let_or_match {
                 IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
@@ -292,7 +291,12 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
         // Only do the check if the type is "spelled out" in the pattern
         if !matches!(
             pat.kind,
-            PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
+            PatKind::Struct(..)
+                | PatKind::TupleStruct(..)
+                | PatKind::Expr(PatExpr {
+                    kind: PatExprKind::Path(..),
+                    ..
+                },)
         ) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
index 2e5a92915d9..bf4f2bff319 100644
--- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
@@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::{PatExpr, PatExprKind, PatKind, RangeEnd};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::{DUMMY_SP, Span};
 
@@ -80,7 +79,7 @@ impl LateLintPass<'_> for ManualRangePatterns {
         // like described https://github.com/rust-lang/rust-clippy/issues/11825)
         if let PatKind::Or(pats) = pat.kind
             && (pats.len() >= 3 || (pats.len() > 1 && pats.iter().any(|p| matches!(p.kind, PatKind::Range(..)))))
-            && !in_external_macro(cx.sess(), pat.span)
+            && !pat.span.in_external_macro(cx.sess().source_map())
         {
             let mut min = Num::dummy(i128::MAX);
             let mut max = Num::dummy(i128::MIN);
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 8aeec89f0bf..469b4b7cf89 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -7,7 +7,6 @@ use clippy_utils::{is_in_const_context, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -60,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             && rem_rhs.span.ctxt() == ctxt
             && add_lhs.span.ctxt() == ctxt
             && add_rhs.span.ctxt() == ctxt
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && self.msrv.meets(msrvs::REM_EUCLID)
             && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !is_in_const_context(cx))
             && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs)
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
index 8f8390b6f3f..7b95399c907 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
@@ -1,6 +1,6 @@
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::GenericArgKind;
 use rustc_session::declare_lint_pass;
@@ -68,7 +68,7 @@ fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> {
 }
 
 fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-    if let PatKind::Path(QPath::Resolved(_, path)) = arm.pat.kind
+    if let PatKind::Expr(PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) = arm.pat.kind
         && let Some(def_id) = path.res.opt_def_id()
         // Since it comes from a pattern binding, we need to get the parent to actually match
         // against it.
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 99a7b8c74be..97e8423695d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -8,7 +8,7 @@ use clippy_utils::{
 };
 use rustc_errors::MultiSpan;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, Expr, HirId, Pat, PatKind};
+use rustc_hir::{Arm, Expr, HirId, Pat, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::Span;
 
@@ -119,7 +119,11 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     }
     match arm.pat.kind {
         PatKind::Binding(..) | PatKind::Wild => true,
-        PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(qpath),
+            hir_id,
+            ..
+        }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
index b1a555b91d1..3deaaf96c1e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
@@ -6,7 +6,7 @@ use rustc_ast::BindingMode;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::Ty;
 use rustc_span::symbol::Ident;
@@ -60,7 +60,16 @@ pub(crate) fn check_match(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Exp
 /// accepted.
 fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool, must_match_err: bool) -> bool {
     match pat.kind {
-        PatKind::Wild | PatKind::Path(..) | PatKind::Binding(_, _, _, None) if can_be_wild => true,
+        PatKind::Wild
+        | PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(_),
+            ..
+        })
+        | PatKind::Binding(_, _, _, None)
+            if can_be_wild =>
+        {
+            true
+        },
         PatKind::TupleStruct(qpath, ..) => {
             is_res_lang_ctor(cx, cx.qpath_res(&qpath, pat.hir_id), ResultErr) == must_match_err
         },
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index 59d37520011..b69294d567d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -7,7 +7,7 @@ use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, ResultErr};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, Pat, PatKind};
+use rustc_hir::{Arm, Expr, Pat, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
 use rustc_span::sym;
@@ -89,7 +89,11 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<(&
     if arms.len() == 2
         && arms.iter().all(|arm| arm.guard.is_none())
         && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind {
-            PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+            PatKind::Expr(PatExpr {
+                hir_id,
+                kind: PatExprKind::Path(qpath),
+                ..
+            }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
             PatKind::TupleStruct(ref qpath, [pat], _) => {
                 matches!(pat.kind, PatKind::Wild)
                     && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index 0b57740064c..2ad55d9bf1f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -11,7 +11,7 @@ use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::def::Res;
-use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
+use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_span::{SyntaxContext, sym};
 
@@ -256,9 +256,11 @@ pub(super) fn try_parse_pattern<'tcx>(
         match pat.kind {
             PatKind::Wild => Some(OptionPat::Wild),
             PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
-            PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone) => {
-                Some(OptionPat::None)
-            },
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(qpath),
+                hir_id,
+                ..
+            }) if is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone) => Some(OptionPat::None),
             PatKind::TupleStruct(ref qpath, [pattern], _)
                 if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionSome) && pat.span.ctxt() == ctxt =>
             {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index 6c123649afc..b1889d26c93 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
+use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatExpr, PatExprKind, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 
@@ -59,7 +59,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
 fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     matches!(
         arm.pat.kind,
-        PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone)
+        PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. }) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone)
     )
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 28e05c273d5..41e4c75f843 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExprKind, PatKind, RangeEnd};
+use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExpr, PatExprKind, PatKind, RangeEnd};
 use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
@@ -292,7 +292,11 @@ impl<'a> NormalizedPat<'a> {
                 Self::Tuple(var_id, pats)
             },
             PatKind::Or(pats) => Self::Or(arena.alloc_from_iter(pats.iter().map(|pat| Self::from_pat(cx, arena, pat)))),
-            PatKind::Path(ref path) => Self::Path(cx.qpath_res(path, pat.hir_id).opt_def_id()),
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path),
+                hir_id,
+                ..
+            }) => Self::Path(cx.qpath_res(path, *hir_id).opt_def_id()),
             PatKind::Tuple(pats, wild_idx) => {
                 let field_count = match cx.typeck_results().pat_ty(pat).kind() {
                     ty::Tuple(subs) => subs.len(),
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 59565560089..11b588b3355 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::{Arm, Expr, PatKind, PathSegment, QPath, Ty, TyKind};
+use rustc_hir::{Arm, Expr, PatExpr, PatExprKind, PatKind, PathSegment, QPath, Ty, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, VariantDef};
 use rustc_span::sym;
@@ -60,8 +60,13 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
         // covered by the set of guards that cover it, but that's really hard to do.
         recurse_or_patterns(arm.pat, |pat| {
             let path = match &peel_hir_pat_refs(pat).0.kind {
-                PatKind::Path(path) => {
-                    let id = match cx.qpath_res(path, pat.hir_id) {
+                PatKind::Expr(PatExpr {
+                    hir_id,
+                    kind: PatExprKind::Path(path),
+                    ..
+                }) => {
+                    // FIXME(clippy): don't you want to use the hir id of the peeled pat?
+                    let id = match cx.qpath_res(path, *hir_id) {
                         Res::Def(
                             DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
                             _,
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index a7fdd483c16..9ca914af281 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -33,7 +33,6 @@ use clippy_utils::{
 };
 use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{SpanData, SyntaxContext};
 
@@ -1054,7 +1053,7 @@ impl_lint_pass!(Matches => [
 impl<'tcx> LateLintPass<'tcx> for Matches {
     #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) {
+        if is_direct_expn_of(expr.span, "matches").is_none() && expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         let from_expansion = expr.span.from_expansion();
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index 0d5575efc22..7e65d586110 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -8,7 +8,9 @@ use clippy_utils::{
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath};
+use rustc_hir::{
+    Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExpr, PatExprKind, PatKind, Path, QPath,
+};
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
@@ -183,7 +185,13 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
             return !matches!(annot, BindingMode(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name;
         },
         // Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
-        (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
+        (
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(QPath::Resolved(_, p_path)),
+                ..
+            }),
+            ExprKind::Path(QPath::Resolved(_, e_path)),
+        ) => {
             return over(p_path.segments, e_path.segments, |p_seg, e_seg| {
                 p_seg.ident.name == e_seg.ident.name
             });
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index edac97344a0..39339966013 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExprKind, PatKind, QPath, UnOp};
+use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_span::{Span, Symbol, sym};
@@ -149,8 +149,12 @@ fn find_method_and_type<'tcx>(
                 None
             }
         },
-        PatKind::Path(ref path) => {
-            if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, check_pat.hir_id)
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(path),
+            hir_id,
+            ..
+        }) => {
+            if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, *hir_id)
                 && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
             {
                 let method = if cx.tcx.lang_items().option_none_variant() == Some(variant_id) {
@@ -351,10 +355,20 @@ fn found_good_method<'tcx>(
                 None
             }
         },
-        (PatKind::TupleStruct(path_left, patterns, _), PatKind::Path(path_right))
-        | (PatKind::Path(path_left), PatKind::TupleStruct(path_right, patterns, _))
-            if patterns.len() == 1 =>
-        {
+        (
+            PatKind::TupleStruct(path_left, patterns, _),
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path_right),
+                ..
+            }),
+        )
+        | (
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path_left),
+                ..
+            }),
+            PatKind::TupleStruct(path_right, patterns, _),
+        ) if patterns.len() == 1 => {
             if let PatKind::Wild = patterns[0].kind {
                 find_good_method_for_match(
                     cx,
@@ -389,7 +403,13 @@ fn found_good_method<'tcx>(
                 None
             }
         },
-        (PatKind::Path(path_left), PatKind::Wild) => get_good_method(cx, arms, path_left),
+        (
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path_left),
+                ..
+            }),
+            PatKind::Wild,
+        ) => get_good_method(cx, arms, path_left),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 38f876fed80..2f46eaaabb3 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -114,7 +114,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
     }
 
     let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
-    let (msg, sugg) = if let PatKind::Path(_) | PatKind::Expr(_) = pat.kind
+    let (msg, sugg) = if let PatKind::Expr(_) = pat.kind
         && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
         && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
         && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
@@ -331,14 +331,16 @@ impl<'a> PatState<'a> {
     #[expect(clippy::similar_names)]
     fn add_pat<'tcx>(&mut self, cx: &'a PatCtxt<'tcx>, pat: &'tcx Pat<'_>) -> bool {
         match pat.kind {
-            PatKind::Path(_)
-                if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
-                    ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
-                    ty::Tuple(tys) => !tys.is_empty(),
-                    ty::Array(_, len) => len.try_to_target_usize(cx.tcx) != Some(1),
-                    ty::Slice(..) => true,
-                    _ => false,
-                } =>
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(_),
+                ..
+            }) if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
+                ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
+                ty::Tuple(tys) => !tys.is_empty(),
+                ty::Array(_, len) => len.try_to_target_usize(cx.tcx) != Some(1),
+                ty::Slice(..) => true,
+                _ => false,
+            } =>
             {
                 matches!(self, Self::Wild)
             },
@@ -386,7 +388,6 @@ impl<'a> PatState<'a> {
             | PatKind::Binding(_, _, _, None)
             | PatKind::Expr(_)
             | PatKind::Range(..)
-            | PatKind::Path(_)
             | PatKind::Never
             | PatKind::Err(_) => {
                 *self = PatState::Wild;
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 5597cd85abc..41528c5dee3 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -11,7 +11,6 @@ use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::symbol::sym;
@@ -188,7 +187,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
     if is_non_aggregate_primitive_type(expr_type) {
         return;
     }
-    if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) {
+    if is_default_equivalent(cx, src) && !expr_span.in_external_macro(cx.tcx.sess.source_map()) {
         let Some(top_crate) = std_or_core(cx) else { return };
         span_lint_and_then(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
index 129e6925428..d550c145466 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -6,13 +6,12 @@ use clippy_utils::{is_from_proc_macro, is_trait_method, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Binder;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_span::{Span, sym};
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) {
-    if !in_external_macro(cx.sess(), expr.span)
+    if !expr.span.in_external_macro(cx.sess().source_map())
         && is_trait_method(cx, expr, sym::Iterator)
         && let ExprKind::Closure(closure) = arg.kind
         && let body = cx.tcx.hir().body(closure.body)
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
index a0c21faaa4c..92c81b3c49d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
@@ -4,7 +4,6 @@ use clippy_utils::macros::{is_assert_macro, root_macro_call};
 use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context, path_to_local};
 use rustc_hir::{Expr, HirId};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::sym;
 
 use super::CONST_IS_EMPTY;
@@ -12,7 +11,7 @@ use super::CONST_IS_EMPTY;
 /// Expression whose initialization depend on a constant conditioned by a `#[cfg(…)]` directive will
 /// not trigger the lint.
 pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_>) {
-    if in_external_macro(cx.sess(), expr.span) || !receiver.span.eq_ctxt(expr.span) {
+    if expr.span.in_external_macro(cx.sess().source_map()) || !receiver.span.eq_ctxt(expr.span) {
         return;
     }
     if let Some(parent) = get_parent_expr(cx, expr) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
index 4a48d4b547c..a56378b5b73 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::{Span, sym};
 
 use super::MANUAL_TRY_FOLD;
@@ -20,7 +19,7 @@ pub(super) fn check<'tcx>(
     fold_span: Span,
     msrv: &Msrv,
 ) {
-    if !in_external_macro(cx.sess(), fold_span)
+    if !fold_span.in_external_macro(cx.sess().source_map())
         && msrv.meets(msrvs::ITERATOR_TRY_FOLD)
         && is_trait_method(cx, expr, sym::Iterator)
         && let init_ty = cx.typeck_results().expr_ty(init)
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 42418318fda..2f447775fa5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -152,7 +152,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, TraitRef, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, sym};
@@ -4625,7 +4624,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
     #[allow(clippy::too_many_lines)]
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
-        if in_external_macro(cx.sess(), impl_item.span) {
+        if impl_item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         let name = impl_item.ident.name.as_str();
@@ -4713,7 +4712,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        if in_external_macro(cx.tcx.sess, item.span) {
+        if item.span.in_external_macro(cx.tcx.sess.source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index a99e21d938c..4119b1d1051 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -6,7 +6,6 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{Visitor, walk_item, walk_trait_item};
 use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem, UsePath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use std::borrow::Cow;
@@ -55,7 +54,7 @@ impl MinIdentChars {
 
     #[expect(clippy::cast_possible_truncation)]
     fn is_ident_too_short(&self, cx: &LateContext<'_>, str: &str, span: Span) -> bool {
-        !in_external_macro(cx.sess(), span)
+        !span.in_external_macro(cx.sess().source_map())
             && str.len() <= self.min_ident_chars_threshold as usize
             && !str.starts_with('_')
             && !str.is_empty()
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index b511b1e46b3..fa0eb9a94b7 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -13,7 +13,6 @@ use rustc_hir::{
     BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
@@ -162,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
             for arg in iter_input_pats(decl, body) {
                 if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind
                     && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id)
-                    && !in_external_macro(cx.tcx.sess, arg.span)
+                    && !arg.span.in_external_macro(cx.tcx.sess.source_map())
                 {
                     span_lint_hir(
                         cx,
@@ -183,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
             && let Some(init) = local.init
             // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
             && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
-            && !in_external_macro(cx.tcx.sess, stmt.span)
+            && !stmt.span.in_external_macro(cx.tcx.sess.source_map())
         {
             let ctxt = local.span.ctxt();
             let mut app = Applicability::MachineApplicable;
@@ -239,7 +238,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span)
+        if expr.span.in_external_macro(cx.sess().source_map())
             || expr.span.desugaring_kind().is_some()
             || in_automatically_derived(cx.tcx, expr.hir_id)
         {
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index 637d6ed3ad2..f880f1f329f 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -14,7 +14,6 @@ use rustc_ast::token;
 use rustc_ast::visit::FnKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 
@@ -350,7 +349,7 @@ impl EarlyLintPass for MiscEarlyLints {
     }
 
     fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
-        if in_external_macro(cx.sess(), pat.span) {
+        if pat.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
@@ -387,7 +386,7 @@ impl EarlyLintPass for MiscEarlyLints {
     }
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs
index 0c81ee5eced..f2cf93465c0 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs
@@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use rustc_ast::{Pat, PatKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 
 use super::REDUNDANT_AT_REST_PATTERN;
 
 pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
-    if !in_external_macro(cx.sess(), pat.span)
+    if !pat.span.in_external_macro(cx.sess().source_map())
         && let PatKind::Slice(slice) = &pat.kind
         && let [one] = &**slice
         && let PatKind::Ident(annotation, ident, Some(rest)) = &one.kind
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 2572e186ce6..962d85c6a9d 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -8,7 +8,6 @@ use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -106,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             return;
         }
 
-        if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) {
+        if span.in_external_macro(cx.tcx.sess.source_map()) || is_entrypoint_fn(cx, def_id.to_def_id()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index bba1b63be27..18385ac9269 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -88,7 +88,7 @@ declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]);
 
 impl<'tcx> LateLintPass<'tcx> for MissingInline {
     fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
-        if rustc_middle::lint::in_external_macro(cx.sess(), it.span) || is_executable_or_proc_macro(cx) {
+        if it.span.in_external_macro(cx.sess().source_map()) || is_executable_or_proc_macro(cx) {
             return;
         }
 
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
-        if rustc_middle::lint::in_external_macro(cx.sess(), impl_item.span) || is_executable_or_proc_macro(cx) {
+        if impl_item.span.in_external_macro(cx.sess().source_map()) || is_executable_or_proc_macro(cx) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index aad6ae52a6d..302db2c914c 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -6,7 +6,6 @@ use hir::{BlockCheckMode, ExprKind, QPath, UnOp};
 use rustc_ast::Mutability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::{DesugaringKind, Span};
@@ -65,7 +64,7 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK])
 impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
         if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_))
-            || in_external_macro(cx.tcx.sess, block.span)
+            || block.span.in_external_macro(cx.tcx.sess.source_map())
             || block.span.is_desugaring(DesugaringKind::Await)
         {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index 0ee851a4cf9..3c4ba5141dd 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_hir};
 use clippy_utils::higher;
 use rustc_hir::{self as hir, AmbigArg, intravisit};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 
@@ -38,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for MutMut {
             && mty.mutbl == hir::Mutability::Mut
             && let hir::TyKind::Ref(_, mty) = mty.ty.kind
             && mty.mutbl == hir::Mutability::Mut
-            && !in_external_macro(cx.sess(), ty.span)
+            && !ty.span.in_external_macro(cx.sess().source_map())
         {
             span_lint(
                 cx,
@@ -56,7 +55,7 @@ pub struct MutVisitor<'a, 'tcx> {
 
 impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
-        if in_external_macro(self.cx.sess(), expr.span) {
+        if expr.span.in_external_macro(self.cx.sess().source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs
index 8e14fbf2f80..7eefb016aca 100644
--- a/src/tools/clippy/clippy_lints/src/needless_if.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_if.rs
@@ -5,7 +5,6 @@ use clippy_utils::source::SpanRangeExt;
 use rustc_errors::Applicability;
 use rustc_hir::{ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -47,7 +46,7 @@ impl LateLintPass<'_> for NeedlessIf {
             && let ExprKind::Block(block, ..) = then.kind
             && block.stmts.is_empty()
             && block.expr.is_none()
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && then.span.check_source_text(cx, |src| {
                 // Ignore
                 // - empty macro expansions
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index fa90ee60612..4f62ba2e58d 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::implements_trait;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
@@ -48,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
         if let ExprKind::Unary(UnOp::Not, inner) = expr.kind
             && let ExprKind::Binary(ref op, left, _) = inner.kind
             && let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             let ty = cx.typeck_results().expr_ty(left);
 
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 688374b5676..cc56df3a23d 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::HirIdSet;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::sym;
 
@@ -69,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
             for assoc_item in *items {
                 if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) {
                     let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
-                    if in_external_macro(cx.sess(), impl_item.span) {
+                    if impl_item.span.in_external_macro(cx.sess().source_map()) {
                         return;
                     }
                     if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index ccd50758044..4d3e6aa79d0 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -12,7 +12,6 @@ use rustc_hir::{
 };
 use rustc_infer::infer::TyCtxtInferExt as _;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -268,7 +267,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 
 fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if let StmtKind::Semi(expr) = stmt.kind
-        && !in_external_macro(cx.sess(), stmt.span)
+        && !stmt.span.in_external_macro(cx.sess().source_map())
         && let ctxt = stmt.span.ctxt()
         && expr.span.ctxt() == ctxt
         && let Some(reduced) = reduce_expression(cx, expr)
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index 94855c46567..dad1e8a3d6a 100644
--- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -5,7 +5,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::EarlyBinder;
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -129,7 +128,7 @@ impl LateLintPass<'_> for NonCanonicalImpls {
         let ExprKind::Block(block, ..) = body.value.kind else {
             return;
         };
-        if in_external_macro(cx.sess(), block.span) || is_from_proc_macro(cx, impl_item) {
+        if block.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, impl_item) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 56c4157d6fe..1a3b43cbb10 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -5,7 +5,6 @@ use rustc_ast::ast::{
 };
 use rustc_ast::visit::{Visitor, walk_block, walk_expr, walk_pat};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, sym};
@@ -381,7 +380,7 @@ impl<'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'_, 'tcx> {
 
 impl EarlyLintPass for NonExpressiveNames {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if in_external_macro(cx.sess(), item.span) {
+        if item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
@@ -396,7 +395,7 @@ impl EarlyLintPass for NonExpressiveNames {
     }
 
     fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) {
-        if in_external_macro(cx.sess(), item.span) {
+        if item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index 793eb5d9456..9542fed3875 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -7,7 +7,6 @@ use rustc_ast::ImplPolarity;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{FieldDef, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::sym;
@@ -81,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
         // We start from `Send` impl instead of `check_field_def()` because
         // single `AdtDef` may have multiple `Send` impls due to generic
         // parameters, and the lint is much easier to implement in this way.
-        if !in_external_macro(cx.tcx.sess, item.span)
+        if !item.span.in_external_macro(cx.tcx.sess.source_map())
             && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
             && let ItemKind::Impl(hir_impl) = &item.kind
             && let Some(trait_ref) = &hir_impl.of_trait
diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
index 312610db042..22116505a1c 100644
--- a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
+++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
@@ -9,7 +9,6 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::{self as hir, BodyId, Expr, ExprKind, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -139,7 +138,7 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic {
             return;
         }
 
-        if in_external_macro(cx.sess(), item.span) {
+        if item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index 2eae9b23746..6e7ee727965 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -4,7 +4,6 @@ use rustc_ast::token::LitKind;
 use rustc_ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::{BytePos, Pos, SpanData};
 
@@ -59,7 +58,7 @@ impl EarlyLintPass for OctalEscapes {
                 LitKind::ByteStr | LitKind::CStr => 2,
                 _ => return,
             })
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             let s = lit.symbol.as_str();
             let mut iter = s.as_bytes().iter();
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index 6d9e75f51d6..de9f055863c 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -7,7 +7,9 @@ use clippy_utils::{
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::def::Res;
-use rustc_hir::{Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp};
+use rustc_hir::{
+    Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, UnOp,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::SyntaxContext;
@@ -281,7 +283,11 @@ fn try_convert_match<'tcx>(
 
 fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     match arm.pat.kind {
-        PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(qpath),
+            hir_id,
+            ..
+        }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
         PatKind::TupleStruct(ref qpath, [first_pat], _) => {
             is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
                 && matches!(first_pat.kind, PatKind::Wild)
diff --git a/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs
index 7f100a746d5..bc1821a48a3 100644
--- a/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs
+++ b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint;
 use clippy_utils::eq_expr_value;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 
@@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for PanickingOverflowChecks {
             && matches!(ty.kind(), ty::Uint(_))
             && ty == typeck.expr_ty(op_rhs)
             && ty == typeck.expr_ty(other)
-            && !in_external_macro(cx.tcx.sess, expr.span)
+            && !expr.span.in_external_macro(cx.tcx.sess.source_map())
             && (eq_expr_value(cx, op_lhs, other) || (commutative && eq_expr_value(cx, op_rhs, other)))
         {
             span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
index 668f09bbfd5..b653b459b04 100644
--- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, Symbol, sym};
 
@@ -136,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingMode::MUT, id, name, None) = local.pat.kind
-            && !in_external_macro(cx.sess(), local.span)
+            && !local.span.in_external_macro(cx.sess().source_map())
             && let ty = cx.typeck_results().pat_ty(local.pat)
             && is_type_diagnostic_item(cx, ty, sym::PathBuf)
         {
@@ -157,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
             && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
             && let [name] = &path.segments
             && let Res::Local(id) = path.res
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && let ty = cx.typeck_results().expr_ty(left)
             && is_type_diagnostic_item(cx, ty, sym::PathBuf)
         {
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index 42fbba8ef6d..8f1a1ee76c6 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -3,7 +3,6 @@ use rustc_hir::{
     Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, intravisit,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
@@ -84,7 +83,7 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);
 impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let StmtKind::Let(local) = stmt.kind {
-            if in_external_macro(cx.sess(), local.pat.span) {
+            if local.pat.span.in_external_macro(cx.sess().source_map()) {
                 return;
             }
             let deref_possible = match local.source {
@@ -171,7 +170,7 @@ fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mut
         if result.is_some() {
             return false;
         }
-        if in_external_macro(cx.sess(), p.span) {
+        if p.span.in_external_macro(cx.sess().source_map()) {
             return true;
         }
         let adjust_pat = match p.kind {
diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs
index 23d0e768c2f..c6e6e782f9d 100644
--- a/src/tools/clippy/clippy_lints/src/raw_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs
@@ -5,7 +5,6 @@ use rustc_ast::ast::{Expr, ExprKind};
 use rustc_ast::token::LitKind;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{BytePos, Pos, Span};
 use std::iter::once;
@@ -72,7 +71,7 @@ impl RawStrings {
 impl EarlyLintPass for RawStrings {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::FormatArgs(format_args) = &expr.kind
-            && !in_external_macro(cx.sess(), format_args.span)
+            && !format_args.span.in_external_macro(cx.sess().source_map())
             && format_args.span.check_source_text(cx, |src| src.starts_with('r'))
             && let Some(str) = snippet_opt(cx.sess(), format_args.span)
             && let count_hash = str.bytes().skip(1).take_while(|b| *b == b'#').count()
@@ -95,7 +94,7 @@ impl EarlyLintPass for RawStrings {
                 LitKind::CStrRaw(max) => ("cr", max),
                 _ => return,
             }
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && expr.span.check_source_text(cx, |src| src.starts_with(prefix))
         {
             self.check_raw_string(cx, lit.symbol.as_str(), expr.span, prefix, max, lit.kind.descr());
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index 3ade6bcee84..65fd312b3a0 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -10,7 +10,6 @@ use rustc_hir::{
     Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::UpvarCapture;
 use rustc_session::declare_lint_pass;
 
@@ -47,7 +46,7 @@ declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]);
 impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let span = expr.span;
-        if !in_external_macro(cx.tcx.sess, span) &&
+        if !span.in_external_macro(cx.tcx.sess.source_map()) &&
             let Some(body_expr) = desugar_async_block(cx, expr) &&
             let Some(expr) = desugar_await(peel_blocks(body_expr)) &&
             // The await prefix must not come from a macro as its content could change in the future.
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index b4dadef57a3..91d023500ca 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -10,7 +10,6 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::ExpnKind;
@@ -138,7 +137,7 @@ fn get_parent_call_exprs<'tcx>(
 
 impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index a27f9b63114..3476f56cf33 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_ast::visit::{Visitor, walk_expr};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -46,7 +45,7 @@ declare_lint_pass!(RedundantElse => [REDUNDANT_ELSE]);
 
 impl EarlyLintPass for RedundantElse {
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) {
-        if in_external_macro(cx.sess(), stmt.span) {
+        if stmt.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         // Only look at expressions that are a whole statement
diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
index 347540e7344..707abc008a8 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
@@ -4,7 +4,6 @@ use clippy_utils::msrvs::{self, Msrv};
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -56,7 +55,7 @@ impl EarlyLintPass for RedundantFieldNames {
             return;
         }
 
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         if let ExprKind::Struct(ref se) = expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 658d93e634c..ebe3e7c2019 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -6,7 +6,6 @@ use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, ByRef, ExprKind, HirId, LetStmt, Node, Pat, PatKind, QPath};
 use rustc_hir_typeck::expr_use_visitor::PlaceBase;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::UpvarCapture;
 use rustc_session::declare_lint_pass;
 use rustc_span::DesugaringKind;
@@ -69,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
             // the local does not affect the code's drop behavior
             && !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr))
             // the local is user-controlled
-            && !in_external_macro(cx.sess(), local.span)
+            && !local.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, expr)
             && !is_by_value_closure_capture(cx, local.hir_id, binding_id)
         {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 8d6b1c7274d..6a17b83b3d0 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -4,7 +4,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::CRATE_DEF_ID;
@@ -51,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
             && !cx.effective_visibilities.is_exported(item.owner_id.def_id)
             && self.is_exported.last() == Some(&false)
             && is_not_macro_export(item)
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
         {
             let span = item.span.with_hi(item.ident.span.hi());
             let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
index 6157adad059..152d7450f5f 100644
--- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingMode::MUT, id, _, None) = local.pat.kind
-            && !in_external_macro(cx.sess(), local.span)
+            && !local.span.in_external_macro(cx.sess().source_map())
             && let Some(init) = get_vec_init_kind(cx, init_expr)
             && !matches!(
                 init,
@@ -101,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
             && let ExprKind::Assign(left, right, _) = expr.kind
             && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
             && let Res::Local(id) = path.res
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && let Some(init) = get_vec_init_kind(cx, right)
             && !matches!(
                 init,
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 42d9cf2c88c..5a25483c397 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -5,7 +5,6 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::{Span, sym};
 
@@ -69,7 +68,7 @@ declare_clippy_lint! {
 declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
 
 fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, owner_id: OwnerId) {
-    if !in_external_macro(cx.sess(), span)
+    if !span.in_external_macro(cx.sess().source_map())
         // If it comes from an external macro, better ignore it.
         && decl.implicit_self.has_implicit_self()
         // We only show this warning for public exported methods.
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 664e984fece..a1cf16e6ce9 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -17,7 +17,6 @@ use rustc_hir::{
     StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::declare_lint_pass;
@@ -191,7 +190,7 @@ fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
 
 impl<'tcx> LateLintPass<'tcx> for Return {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if !in_external_macro(cx.sess(), stmt.span)
+        if !stmt.span.in_external_macro(cx.sess().source_map())
             && let StmtKind::Semi(expr) = stmt.kind
             && let ExprKind::Ret(Some(ret)) = expr.kind
             // return Err(...)? desugars to a match
@@ -237,8 +236,8 @@ impl<'tcx> LateLintPass<'tcx> for Return {
             && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
             && path_to_local_id(retexpr, local_id)
             && !last_statement_borrows(cx, initexpr)
-            && !in_external_macro(cx.sess(), initexpr.span)
-            && !in_external_macro(cx.sess(), retexpr.span)
+            && !initexpr.span.in_external_macro(cx.sess().source_map())
+            && !retexpr.span.in_external_macro(cx.sess().source_map())
             && !local.span.from_expansion()
             && !span_contains_cfg(cx, stmt.span.between(retexpr.span))
         {
diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
index 0176077c70e..fdbccbaa8a5 100644
--- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
@@ -6,7 +6,6 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{Expr, ExprKind, HirId, Node};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -88,7 +87,7 @@ impl SingleCallFn {
         fn_span: Span,
     ) -> bool {
         (self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id))
-            || in_external_macro(cx.sess(), fn_span)
+            || fn_span.in_external_macro(cx.sess().source_map())
             || cx
                 .tcx
                 .hir()
diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
index d92b890950a..50a6ee316c8 100644
--- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
+++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{GenericParam, GenericParamKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -42,7 +41,7 @@ declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]);
 
 impl EarlyLintPass for SingleCharLifetimeNames {
     fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) {
-        if in_external_macro(ctx.sess(), param.ident.span) {
+        if param.ident.span.in_external_macro(ctx.sess().source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index 8ec7bfe9edd..59c13a1e2c5 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -8,7 +8,6 @@ use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{HirId, Path, PathSegment};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
 use rustc_span::{Span, sym};
@@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
         if let Res::Def(_, def_id) = path.res
             && let Some(first_segment) = get_first_segment(path)
             && is_stable(cx, def_id, &self.msrv)
-            && !in_external_macro(cx.sess(), path.span)
+            && !path.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, &first_segment.ident)
         {
             let (lint, used_mod, replace_with) = match first_segment.ident.name {
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 2925f355d0b..6164a6191db 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -9,7 +9,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
@@ -147,7 +146,7 @@ declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]);
 
 impl<'tcx> LateLintPass<'tcx> for StringAdd {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), e.span) {
+        if e.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         match e.kind {
@@ -284,7 +283,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
             );
         }
 
-        if !in_external_macro(cx.sess(), e.span)
+        if !e.span.in_external_macro(cx.sess().source_map())
             && let ExprKind::MethodCall(path, receiver, ..) = &e.kind
             && path.ident.name.as_str() == "as_bytes"
             && let ExprKind::Lit(lit) = &receiver.kind
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
index d1d822a5532..e55d17818e4 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -5,7 +5,6 @@ use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -32,7 +31,7 @@ declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]);
 
 impl LateLintPass<'_> for ConfusingXorAndPow {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if !in_external_macro(cx.sess(), expr.span)
+        if !expr.span.in_external_macro(cx.sess().source_map())
             && let ExprKind::Binary(op, left, right) = &expr.kind
             && op.node == BinOpKind::BitXor
             && left.span.eq_ctxt(right.span)
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 9b4c3d275ae..7176d533b61 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -12,7 +12,6 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
@@ -212,7 +211,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
         if let Some((lhs0, rhs0)) = parse(first)
             && let Some((lhs1, rhs1)) = parse(second)
             && first.span.eq_ctxt(second.span)
-			&& !in_external_macro(cx.sess(), first.span)
+			&& !first.span.in_external_macro(cx.sess().source_map())
             && is_same(cx, lhs0, rhs1)
             && is_same(cx, lhs1, rhs0)
 			&& !is_same(cx, lhs1, rhs1) // Ignore a = b; a = a (#10421)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
index bed4e60ba62..4961dd6b280 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use rustc_errors::Applicability;
 use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 
 use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS;
@@ -44,7 +43,7 @@ pub(super) fn check<'tcx>(
     expr_hir_id: HirId,
 ) -> bool {
     let last = path.segments.last().unwrap();
-    if in_external_macro(cx.tcx.sess, last.ident.span) {
+    if last.ident.span.in_external_macro(cx.tcx.sess.source_map()) {
         // If it comes from a non-local macro, we ignore it.
         return false;
     }
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index 008e09dd8bd..c7aefc65f70 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -7,7 +7,6 @@ use itertools::Itertools;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
 use std::iter::once;
@@ -56,7 +55,7 @@ impl TupleArrayConversions {
 
 impl LateLintPass<'_> for TupleArrayConversions {
     fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if in_external_macro(cx.sess(), expr.span) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
+        if expr.span.in_external_macro(cx.sess().source_map()) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 45d730985bb..5e5d6a9e333 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -11,7 +11,6 @@ use rustc_hir as hir;
 use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext};
 
@@ -111,7 +110,7 @@ impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECES
 impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
         if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
-            && !in_external_macro(cx.tcx.sess, block.span)
+            && !block.span.in_external_macro(cx.tcx.sess.source_map())
             && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
             && !is_unsafe_from_proc_macro(cx, block.span)
             && !block_has_safety_comment(cx, block.span)
@@ -143,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
 
         if let Some(tail) = block.expr
             && !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, tail.hir_id)
-            && !in_external_macro(cx.tcx.sess, tail.span)
+            && !tail.span.in_external_macro(cx.tcx.sess.source_map())
             && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, tail.span, tail.hir_id)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, tail, pos)
         {
@@ -167,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
             return;
         };
         if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, stmt.hir_id)
-            && !in_external_macro(cx.tcx.sess, stmt.span)
+            && !stmt.span.in_external_macro(cx.tcx.sess.source_map())
             && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, stmt.span, stmt.hir_id)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, expr, pos)
         {
@@ -184,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if in_external_macro(cx.tcx.sess, item.span) {
+        if item.span.in_external_macro(cx.tcx.sess.source_map()) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
index ee9ef017253..b342f37f0c5 100644
--- a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
+++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
@@ -3,7 +3,6 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp};
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
@@ -40,7 +39,7 @@ declare_lint_pass!(UninhabitedReferences => [UNINHABITED_REFERENCES]);
 
 impl LateLintPass<'_> for UninhabitedReferences {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        if in_external_macro(cx.tcx.sess, expr.span) {
+        if expr.span.in_external_macro(cx.tcx.sess.source_map()) {
             return;
         }
 
@@ -66,7 +65,7 @@ impl LateLintPass<'_> for UninhabitedReferences {
         span: Span,
         _: LocalDefId,
     ) {
-        if in_external_macro(cx.tcx.sess, span) || matches!(kind, FnKind::Closure) {
+        if span.in_external_macro(cx.tcx.sess.source_map()) || matches!(kind, FnKind::Closure) {
             return;
         }
         if let FnRetTy::Return(hir_ty) = fndecl.output
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 93ed15777e0..7803d5115c9 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -4,7 +4,6 @@ use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
 use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while};
 use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::{Span, sym};
@@ -64,7 +63,7 @@ declare_lint_pass!(UninitVec => [UNINIT_VEC]);
 // Threads: https://github.com/rust-lang/rust-clippy/pull/7682#discussion_r710998368
 impl<'tcx> LateLintPass<'tcx> for UninitVec {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
-        if !in_external_macro(cx.tcx.sess, block.span) {
+        if !block.span.in_external_macro(cx.tcx.sess.source_map()) {
             for w in block.stmts.windows(2) {
                 if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind {
                     handle_uninit_vec_pair(cx, &w[0], expr);
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index 660bdb9e2be..00b80e827d8 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -7,7 +7,6 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{Visitor, walk_body};
 use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::{in_external_macro, is_from_async_await};
 use rustc_middle::ty;
 
 use super::LET_UNIT_VALUE;
@@ -22,8 +21,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
 
     if let Some(init) = local.init
         && !local.pat.span.from_expansion()
-        && !in_external_macro(cx.sess(), local.span)
-        && !is_from_async_await(local.span)
+        && !local.span.in_external_macro(cx.sess().source_map())
+        && !local.span.is_from_async_await()
         && cx.typeck_results().pat_ty(local.pat).is_unit()
     {
         // skip `let awa = ()`
diff --git a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
index 0c0d10eac5b..958f19d1833 100644
--- a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
@@ -4,7 +4,6 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
@@ -39,7 +38,7 @@ impl LateLintPass<'_> for UnusedResultOk {
             && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
             && ok_path.ident.as_str() == "ok"
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
-            && !in_external_macro(cx.sess(), stmt.span)
+            && !stmt.span.in_external_macro(cx.sess().source_map())
         {
             let ctxt = expr.span.ctxt();
             let mut applicability = Applicability::MaybeIncorrect;
diff --git a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs
index 17ee5fc20ca..f8341583435 100644
--- a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Item, ItemKind, UseKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext as _};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Visibility;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
@@ -63,7 +62,7 @@ impl_lint_pass!(UnusedTraitNames => [UNUSED_TRAIT_NAMES]);
 impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if self.msrv.meets(msrvs::UNDERSCORE_IMPORTS)
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && let ItemKind::Use(path, UseKind::Single) = item.kind
             // Ignore imports that already use Underscore
             && item.ident.name != kw::Underscore
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index eaa119b045f..6a952c0d97a 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -8,7 +8,6 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegmen
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::declare_lint_pass;
@@ -292,7 +291,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // Shouldn't lint when `expr` is in macro.
-        if in_external_macro(self.cx.tcx.sess, expr.span) {
+        if expr.span.in_external_macro(self.cx.tcx.sess.source_map()) {
             return;
         }
         if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) {
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index c3843279ba2..3449468ef48 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -4,7 +4,6 @@ use core::mem::replace;
 use rustc_errors::Applicability;
 use rustc_hir::{HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::Ident;
 
@@ -126,7 +125,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive
 impl LateLintPass<'_> for UpperCaseAcronyms {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
         // do not lint public items or in macros
-        if in_external_macro(cx.sess(), it.span)
+        if it.span.in_external_macro(cx.sess().source_map())
             || (self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(it.owner_id.def_id))
         {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 84b6430294f..47ce2243aa0 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -10,7 +10,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
     self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
-    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
+    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
 };
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
@@ -258,7 +258,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
             && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last()
             // get the path from the pattern
-            && let PatKind::Path(QPath::Resolved(_, path))
+            && let PatKind::Expr(&PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. })
                  | PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
                  | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind
             && cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity()
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 4dcc8ac7fb0..6bad78cf871 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -708,11 +708,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.qpath(qpath);
                 self.slice(fields, |pat| self.pat(pat));
             },
-            PatKind::Path(ref qpath) => {
-                bind!(self, qpath);
-                kind!("Path(ref {qpath})");
-                self.qpath(qpath);
-            },
             PatKind::Tuple(fields, skip_pos) => {
                 bind!(self, fields);
                 kind!("Tuple({fields}, {skip_pos:?})");
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index d87d554eb07..3c23662e9d1 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -8,7 +8,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, Symbol};
 
@@ -158,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingMode::MUT, id, name, None) = local.pat.kind
-            && !in_external_macro(cx.sess(), local.span)
+            && !local.span.in_external_macro(cx.sess().source_map())
             && let Some(init) = get_vec_init_kind(cx, init_expr)
             && !matches!(init, VecInitKind::WithExprCapacity(_))
         {
@@ -181,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
             && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
             && let [name] = &path.segments
             && let Res::Local(id) = path.res
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && let Some(init) = get_vec_init_kind(cx, right)
             && !matches!(init, VecInitKind::WithExprCapacity(_))
         {
diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs
index 2e5fc5834e2..d17b3df9921 100644
--- a/src/tools/clippy/clippy_lints/src/visibility.rs
+++ b/src/tools/clippy/clippy_lints/src/visibility.rs
@@ -3,7 +3,6 @@ use clippy_utils::source::SpanRangeExt;
 use rustc_ast::ast::{Item, VisibilityKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 use rustc_span::symbol::kw;
@@ -79,7 +78,7 @@ declare_lint_pass!(Visibility => [NEEDLESS_PUB_SELF, PUB_WITH_SHORTHAND, PUB_WIT
 
 impl EarlyLintPass for Visibility {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if !in_external_macro(cx.sess(), item.span)
+        if !item.span.in_external_macro(cx.sess().source_map())
             && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind
         {
             if **path == kw::SelfLower && !is_from_proc_macro(cx, item.vis.span) {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index d76231a6eea..d0eb5318e64 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -524,7 +524,6 @@ impl HirEqInterExpr<'_, '_, '_> {
                 }
                 eq
             },
-            (PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
             (&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r),
             (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
@@ -1120,7 +1119,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_pat(pat);
                 }
             },
-            PatKind::Path(ref qpath) => self.hash_qpath(qpath),
             PatKind::Range(s, e, i) => {
                 if let Some(s) = s {
                     self.hash_pat_expr(s);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index e471dfb6ef1..5a5227af907 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -106,8 +106,8 @@ use rustc_hir::{
     self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext,
     Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
     ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
-    PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
-    TyKind, UnOp, def,
+    PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
+    TraitItemRef, TraitRef, TyKind, UnOp, def,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -560,7 +560,20 @@ macro_rules! maybe_path {
     };
 }
 maybe_path!(Expr, ExprKind);
-maybe_path!(Pat, PatKind);
+impl<'hir> MaybePath<'hir> for Pat<'hir> {
+    fn hir_id(&self) -> HirId {
+        self.hir_id
+    }
+    fn qpath_opt(&self) -> Option<&QPath<'hir>> {
+        match &self.kind {
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(qpath),
+                ..
+            }) => Some(qpath),
+            _ => None,
+        }
+    }
+}
 maybe_path!(Ty, TyKind);
 
 /// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
@@ -1753,7 +1766,11 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
         PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
         PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
         PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
-        PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(qpath),
+            hir_id,
+            ..
+        }) => is_enum_variant(cx, qpath, *hir_id),
         PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
             are_refutable(cx, pats)
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 287bdc9a6fd..0aaef91e48a 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
@@ -116,6 +116,7 @@ fn check_rvalue<'tcx>(
         Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
         Rvalue::Repeat(operand, _)
         | Rvalue::Use(operand)
+        | Rvalue::WrapUnsafeBinder(operand, _)
         | Rvalue::Cast(
             CastKind::PointerWithExposedProvenance
             | CastKind::IntToInt
@@ -289,7 +290,8 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Subtype(_)
-            | ProjectionElem::Index(_) => {},
+            | ProjectionElem::Index(_)
+            | ProjectionElem::UnwrapUnsafeBinder(_) => {},
         }
     }
 
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 8201f332d33..e4092bcd105 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -166,6 +166,8 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
         // MIR passes can be enabled / disabled separately, we should figure out, what passes to
         // use for Clippy.
         config.opts.unstable_opts.mir_opt_level = Some(0);
+        config.opts.unstable_opts.mir_enable_passes =
+            vec![("CheckNull".to_owned(), false), ("CheckAlignment".to_owned(), false)];
 
         // Disable flattening and inlining of format_args!(), so the HIR matches with the AST.
         config.opts.unstable_opts.flatten_format_args = false;
@@ -195,7 +197,7 @@ pub fn main() {
     });
 
     exit(rustc_driver::catch_with_exit_code(move || {
-        let mut orig_args = rustc_driver::args::raw_args(&early_dcx)?;
+        let mut orig_args = rustc_driver::args::raw_args(&early_dcx);
 
         let has_sysroot_arg = |args: &mut [String]| -> bool {
             if has_arg(args, "--sysroot") {
@@ -237,7 +239,7 @@ pub fn main() {
             pass_sysroot_env_if_given(&mut args, sys_root_env);
 
             rustc_driver::run_compiler(&args, &mut DefaultCallbacks);
-            return Ok(());
+            return;
         }
 
         if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -299,7 +301,6 @@ pub fn main() {
         } else {
             rustc_driver::run_compiler(&args, &mut RustcCallbacks { clippy_args_var });
         }
-        Ok(())
     }))
 }
 
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index acdb3cbdd45..a7ac875d0a3 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -39,6 +39,10 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-android",
     "ignore-apple",
     "ignore-arm",
+    "ignore-arm-unknown-linux-gnueabi",
+    "ignore-arm-unknown-linux-gnueabihf",
+    "ignore-arm-unknown-linux-musleabi",
+    "ignore-arm-unknown-linux-musleabihf",
     "ignore-avr",
     "ignore-beta",
     "ignore-cdb",
@@ -177,6 +181,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-bpf",
     "only-cdb",
     "only-dist",
+    "only-emscripten",
     "only-gnu",
     "only-i686-pc-windows-gnu",
     "only-i686-pc-windows-msvc",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 8c96554738e..452a2e9a9d5 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -882,14 +882,6 @@ fn iter_header(
         }
         let ln = ln.trim();
 
-        // Assume that any directives will be found before the first module or function. This
-        // doesn't seem to be an optimization with a warm page cache. Maybe with a cold one.
-        // FIXME(jieyouxu): this will cause `//@` directives in the rest of the test file to
-        // not be checked.
-        if ln.starts_with("fn") || ln.starts_with("mod") {
-            return;
-        }
-
         let Some(directive_line) = line_directive(line_number, comment, ln) else {
             continue;
         };
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index ca48abda5fc..0e2da2b02ca 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1417,9 +1417,7 @@ impl<'test> TestCx<'test> {
     }
 
     fn is_rustdoc(&self) -> bool {
-        self.config.src_base.ends_with("rustdoc-ui")
-            || self.config.src_base.ends_with("rustdoc-js")
-            || self.config.src_base.ends_with("rustdoc-json")
+        matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json")
     }
 
     fn get_mir_dump_dir(&self) -> PathBuf {
diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs
index 31fdb0a5d13..bf7eb2e109a 100644
--- a/src/tools/compiletest/src/runtest/rustdoc_json.rs
+++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs
@@ -16,13 +16,12 @@ impl TestCx<'_> {
             self.fatal_proc_rec("rustdoc failed!", &proc_res);
         }
 
-        let root = self.config.find_rust_src_root().unwrap();
         let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap());
         json_out.set_extension("json");
         let res = self.run_command_to_procres(
             Command::new(self.config.jsondocck_path.as_ref().unwrap())
                 .arg("--doc-dir")
-                .arg(root.join(&out_dir))
+                .arg(&out_dir)
                 .arg("--template")
                 .arg(&self.testpaths.file),
         );
diff --git a/src/tools/enzyme b/src/tools/enzyme
-Subproject 2fe5164a2423dd67ef25e2c4fb204fd06362494
+Subproject 0e5fa4a3d475f4dece489c9e06b11164f83789f
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 363b96fdff1..57a757f9085 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -351,7 +351,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.13.3+wasi-0.2.2",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -529,12 +541,12 @@ dependencies = [
  "chrono-tz",
  "colored",
  "directories",
- "getrandom",
+ "getrandom 0.3.1",
  "libc",
  "libffi",
  "libloading",
  "measureme",
- "rand",
+ "rand 0.9.0",
  "regex",
  "rustc_version",
  "smallvec",
@@ -662,7 +674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
 dependencies = [
  "phf_shared",
- "rand",
+ "rand 0.8.5",
 ]
 
 [[package]]
@@ -692,7 +704,7 @@ version = "0.2.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
 dependencies = [
- "zerocopy",
+ "zerocopy 0.7.35",
 ]
 
 [[package]]
@@ -729,19 +741,28 @@ version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
- "libc",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
+dependencies = [
  "rand_chacha",
- "rand_core",
+ "rand_core 0.9.0",
+ "zerocopy 0.8.14",
 ]
 
 [[package]]
 name = "rand_chacha"
-version = "0.3.1"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
 dependencies = [
  "ppv-lite86",
- "rand_core",
+ "rand_core 0.9.0",
 ]
 
 [[package]]
@@ -749,8 +770,15 @@ name = "rand_core"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+
+[[package]]
+name = "rand_core"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
 dependencies = [
- "getrandom",
+ "getrandom 0.3.1",
+ "zerocopy 0.8.14",
 ]
 
 [[package]]
@@ -768,7 +796,7 @@ version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
  "libredox",
  "thiserror",
 ]
@@ -1051,9 +1079,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
 name = "ui_test"
-version = "0.26.5"
+version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32ee4c40e5a5f9fa6864ff976473e5d6a6e9884b6ce68b40690d9f87e1994c83"
+checksum = "7484683d60d50ca1d1b6433c3dbf6c5ad71d20387acdcfb16fe79573f3fba576"
 dependencies = [
  "annotate-snippets",
  "anyhow",
@@ -1106,6 +1134,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
+name = "wasi"
+version = "0.13.3+wasi-0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
 name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1245,13 +1282,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
+name = "wit-bindgen-rt"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
 name = "zerocopy"
 version = "0.7.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
 dependencies = [
  "byteorder",
- "zerocopy-derive",
+ "zerocopy-derive 0.7.35",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468"
+dependencies = [
+ "zerocopy-derive 0.8.14",
 ]
 
 [[package]]
@@ -1264,3 +1319,14 @@ dependencies = [
  "quote",
  "syn",
 ]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 6e8e270985e..de80722fc3d 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -18,8 +18,8 @@ test = false    # we have no unit tests
 doctest = false # and no doc tests
 
 [dependencies]
-getrandom = { version = "0.2", features = ["std"] }
-rand = "0.8"
+getrandom = { version = "0.3", features = ["std"] }
+rand = "0.9"
 smallvec = { version = "1.7", features = ["drain_filter"] }
 aes = { version = "0.8.3", features = ["hazmat"] }
 measureme = "11"
@@ -47,8 +47,8 @@ windows-sys = { version = "0.52", features = [
 ] }
 
 [dev-dependencies]
+ui_test = "0.28.0"
 colored = "2"
-ui_test = "0.26.5"
 rustc_version = "0.4"
 regex = "1.5.5"
 tempfile = "3"
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index fb3fc621565..5583030b490 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -14,9 +14,7 @@ function endgroup {
 begingroup "Building Miri"
 
 # Global configuration
-# We are getting some odd linker warnings on macOS, make sure they do not fail the build.
-# (See <https://github.com/rust-lang/rust/issues/136086>.)
-export RUSTFLAGS="-D warnings -A linker-messages"
+export RUSTFLAGS="-D warnings"
 export CARGO_INCREMENTAL=0
 export CARGO_EXTRA_FLAGS="--locked"
 
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 0d405f532fc..6e84524c8aa 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-2f0ad2a71e4a4528bb80bcb24bf8fa4e50cb87c2
+6dd75f0d6802f56564f5f9c947a85ded286d3986
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index 3d0fc5590eb..a4f2a117b18 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -217,7 +217,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // We have to pick a fresh address.
             // Leave some space to the previous allocation, to give it some chance to be less aligned.
             // We ensure that `(global_state.next_base_addr + slack) % 16` is uniformly distributed.
-            let slack = rng.gen_range(0..16);
+            let slack = rng.random_range(0..16);
             // From next_base_addr + slack, round up to adjust for alignment.
             let base_addr = global_state
                 .next_base_addr
diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
index b0c7ee7dff5..c0d24a9fbbc 100644
--- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs
+++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
@@ -58,7 +58,7 @@ impl ReusePool {
         // We don't remember stack addresses: there's a lot of them (so the perf impact is big),
         // and we only want to reuse stack slots within the same thread or else we'll add a lot of
         // undesired synchronization.
-        if kind == MemoryKind::Stack || !rng.gen_bool(self.address_reuse_rate) {
+        if kind == MemoryKind::Stack || !rng.random_bool(self.address_reuse_rate) {
             return;
         }
         let clock = clock();
@@ -88,10 +88,10 @@ impl ReusePool {
         thread: ThreadId,
     ) -> Option<(u64, Option<VClock>)> {
         // Determine whether we'll even attempt a reuse. As above, we don't do reuse for stack addresses.
-        if kind == MemoryKind::Stack || !rng.gen_bool(self.address_reuse_rate) {
+        if kind == MemoryKind::Stack || !rng.random_bool(self.address_reuse_rate) {
             return None;
         }
-        let cross_thread_reuse = rng.gen_bool(self.address_reuse_cross_thread_rate);
+        let cross_thread_reuse = rng.random_bool(self.address_reuse_cross_thread_rate);
         // Determine the pool to take this from.
         let subpool = self.subpool(align);
         // Let's see if we can find something of the right size. We want to find the full range of
@@ -118,7 +118,7 @@ impl ReusePool {
             return None;
         }
         // Pick a random element with the desired size.
-        let idx = rng.gen_range(begin..end);
+        let idx = rng.random_range(begin..end);
         // Remove it from the pool and return.
         let (chosen_addr, chosen_size, chosen_thread, clock) = subpool.remove(idx);
         debug_assert!(chosen_size >= size && chosen_addr % align.bytes() == 0);
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 988a0be6327..685f5670ab4 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -379,10 +379,8 @@ fn run_compiler_and_exit(
     callbacks: &mut (dyn rustc_driver::Callbacks + Send),
 ) -> ! {
     // Invoke compiler, and handle return code.
-    let exit_code = rustc_driver::catch_with_exit_code(move || {
-        rustc_driver::run_compiler(args, callbacks);
-        Ok(())
-    });
+    let exit_code =
+        rustc_driver::catch_with_exit_code(move || rustc_driver::run_compiler(args, callbacks));
     std::process::exit(exit_code)
 }
 
@@ -461,7 +459,7 @@ fn main() {
     // (`install_ice_hook` might change `RUST_BACKTRACE`.)
     let env_snapshot = env::vars_os().collect::<Vec<_>>();
 
-    let args = rustc_driver::args::raw_args(&early_dcx)
+    let args = rustc_driver::catch_fatal_errors(|| rustc_driver::args::raw_args(&early_dcx))
         .unwrap_or_else(|_| std::process::exit(rustc_driver::EXIT_FAILURE));
 
     // Install the ctrlc handler that sets `rustc_const_eval::CTRL_C_RECEIVED`, even if
@@ -723,8 +721,8 @@ fn main() {
 
     // Ensure we have parallelism for many-seeds mode.
     if many_seeds.is_some() && !rustc_args.iter().any(|arg| arg.starts_with("-Zthreads=")) {
-        // Clamp to 8 threads; things get a lot less efficient beyond that due to lock contention.
-        let threads = std::thread::available_parallelism().map_or(1, |n| n.get()).min(8);
+        // Clamp to 10 threads; things get a lot less efficient beyond that due to lock contention.
+        let threads = std::thread::available_parallelism().map_or(1, |n| n.get()).min(10);
         rustc_args.push(format!("-Zthreads={threads}"));
     }
     let many_seeds =
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index bcc8668dbc1..18a5a0612bb 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -865,7 +865,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let new_perm = NewPermission::from_ref_ty(val.layout.ty, kind, this);
         let cause = match kind {
-            RetagKind::TwoPhase { .. } => RetagCause::TwoPhase,
+            RetagKind::TwoPhase => RetagCause::TwoPhase,
             RetagKind::FnEntry => unreachable!(),
             RetagKind::Raw | RetagKind::Default => RetagCause::Normal,
         };
@@ -880,7 +880,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let retag_fields = this.machine.borrow_tracker.as_mut().unwrap().get_mut().retag_fields;
         let retag_cause = match kind {
-            RetagKind::TwoPhase { .. } => unreachable!(), // can only happen in `retag_ptr_value`
+            RetagKind::TwoPhase => unreachable!(), // can only happen in `retag_ptr_value`
             RetagKind::FnEntry => RetagCause::FnEntry,
             RetagKind::Default | RetagKind::Raw => RetagCause::Normal,
         };
@@ -904,10 +904,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 new_perm: NewPermission,
             ) -> InterpResult<'tcx> {
                 let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
-                let val = self.ecx.sb_retag_reference(&val, new_perm, RetagInfo {
-                    cause: self.retag_cause,
-                    in_field: self.in_field,
-                })?;
+                let val = self.ecx.sb_retag_reference(
+                    &val,
+                    new_perm,
+                    RetagInfo { cause: self.retag_cause, in_field: self.in_field },
+                )?;
                 self.ecx.write_immediate(*val, place)?;
                 interp_ok(())
             }
@@ -996,10 +997,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             access: Some(AccessKind::Write),
             protector: Some(ProtectorKind::StrongProtector),
         };
-        this.sb_retag_place(place, new_perm, RetagInfo {
-            cause: RetagCause::InPlaceFnPassing,
-            in_field: false,
-        })
+        this.sb_retag_place(
+            place,
+            new_perm,
+            RetagInfo { cause: RetagCause::InPlaceFnPassing, in_field: false },
+        )
     }
 
     /// Mark the given tag as exposed. It was found on a pointer with the given AllocId.
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 5d7c3d8c219..5c12ce39d10 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -379,14 +379,18 @@ pub mod diagnostics {
     use super::*;
     impl fmt::Display for PermissionPriv {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            write!(f, "{}", match self {
-                ReservedFrz { conflicted: false } => "Reserved",
-                ReservedFrz { conflicted: true } => "Reserved (conflicted)",
-                ReservedIM => "Reserved (interior mutable)",
-                Active => "Active",
-                Frozen => "Frozen",
-                Disabled => "Disabled",
-            })
+            write!(
+                f,
+                "{}",
+                match self {
+                    ReservedFrz { conflicted: false } => "Reserved",
+                    ReservedFrz { conflicted: true } => "Reserved (conflicted)",
+                    ReservedIM => "Reserved (interior mutable)",
+                    Active => "Active",
+                    Frozen => "Frozen",
+                    Disabled => "Disabled",
+                }
+            )
         }
     }
 
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 fd69278f20a..3389b1c602c 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -581,15 +581,18 @@ impl Tree {
             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(root_idx, Node {
-                tag: root_tag,
-                parent: None,
-                children: SmallVec::default(),
-                default_initial_perm: root_default_perm,
-                // The root may never be skipped, all accesses will be local.
-                default_initial_idempotent_foreign_access: IdempotentForeignAccess::None,
-                debug_info,
-            });
+            nodes.insert(
+                root_idx,
+                Node {
+                    tag: root_tag,
+                    parent: None,
+                    children: SmallVec::default(),
+                    default_initial_perm: root_default_perm,
+                    // The root may never be skipped, all accesses will be local.
+                    default_initial_idempotent_foreign_access: IdempotentForeignAccess::None,
+                    debug_info,
+                },
+            );
             nodes
         };
         let rperms = {
@@ -624,14 +627,17 @@ impl<'tcx> Tree {
         let parent_idx = self.tag_mapping.get(&parent_tag).unwrap();
         let strongest_idempotent = default_initial_perm.strongest_idempotent_foreign_access(prot);
         // Create the node
-        self.nodes.insert(idx, Node {
-            tag: new_tag,
-            parent: Some(parent_idx),
-            children: SmallVec::default(),
-            default_initial_perm,
-            default_initial_idempotent_foreign_access: strongest_idempotent,
-            debug_info: NodeDebugInfo::new(new_tag, default_initial_perm, span),
-        });
+        self.nodes.insert(
+            idx,
+            Node {
+                tag: new_tag,
+                parent: Some(parent_idx),
+                children: SmallVec::default(),
+                default_initial_perm,
+                default_initial_idempotent_foreign_access: strongest_idempotent,
+                debug_info: NodeDebugInfo::new(new_tag, default_initial_perm, span),
+            },
+        );
         // Register new_tag as a child of parent_tag
         self.nodes.get_mut(parent_idx).unwrap().children.push(idx);
         // Initialize perms
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 4cdc9348dc9..b1ca434361b 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -830,7 +830,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate;
         let cmpxchg_success = eq.to_scalar().to_bool()?
             && if can_fail_spuriously {
-                this.machine.rng.get_mut().gen_bool(success_rate)
+                this.machine.rng.get_mut().random_bool(success_rate)
             } else {
                 true
             };
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index 14c72e9398a..268268848ed 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -128,7 +128,7 @@ struct Condvar {
 /// The futex state.
 #[derive(Default, Debug)]
 struct Futex {
-    waiters: VecDeque<FutexWaiter>,
+    waiters: Vec<FutexWaiter>,
     /// Tracks the happens-before relationship
     /// between a futex-wake and a futex-wait
     /// during a non-spurious wake event.
@@ -140,6 +140,12 @@ struct Futex {
 #[derive(Default, Clone)]
 pub struct FutexRef(Rc<RefCell<Futex>>);
 
+impl FutexRef {
+    pub fn waiters(&self) -> usize {
+        self.0.borrow().waiters.len()
+    }
+}
+
 impl VisitProvenance for FutexRef {
     fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
         // No provenance in `Futex`.
@@ -728,25 +734,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(true)
     }
 
-    /// Wait for the futex to be signaled, or a timeout.
-    /// On a signal, `retval_succ` is written to `dest`.
-    /// On a timeout, `retval_timeout` is written to `dest` and `errno_timeout` is set as the last error.
+    /// Wait for the futex to be signaled, or a timeout. Once the thread is
+    /// unblocked, `callback` is called with the unblock reason.
     fn futex_wait(
         &mut self,
         futex_ref: FutexRef,
         bitset: u32,
         timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>,
-        retval_succ: Scalar,
-        retval_timeout: Scalar,
-        dest: MPlaceTy<'tcx>,
-        errno_timeout: IoError,
+        callback: DynUnblockCallback<'tcx>,
     ) {
         let this = self.eval_context_mut();
         let thread = this.active_thread();
         let mut futex = futex_ref.0.borrow_mut();
         let waiters = &mut futex.waiters;
         assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting");
-        waiters.push_back(FutexWaiter { thread, bitset });
+        waiters.push(FutexWaiter { thread, bitset });
         drop(futex);
 
         this.block_thread(
@@ -755,10 +757,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             callback!(
                 @capture<'tcx> {
                     futex_ref: FutexRef,
-                    retval_succ: Scalar,
-                    retval_timeout: Scalar,
-                    dest: MPlaceTy<'tcx>,
-                    errno_timeout: IoError,
+                    callback: DynUnblockCallback<'tcx>,
                 }
                 |this, unblock: UnblockKind| {
                     match unblock {
@@ -768,29 +767,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                             if let Some(data_race) = &this.machine.data_race {
                                 data_race.acquire_clock(&futex.clock, &this.machine.threads);
                             }
-                            // Write the return value.
-                            this.write_scalar(retval_succ, &dest)?;
-                            interp_ok(())
                         },
                         UnblockKind::TimedOut => {
                             // Remove the waiter from the futex.
                             let thread = this.active_thread();
                             let mut futex = futex_ref.0.borrow_mut();
                             futex.waiters.retain(|waiter| waiter.thread != thread);
-                            // Set errno and write return value.
-                            this.set_last_error(errno_timeout)?;
-                            this.write_scalar(retval_timeout, &dest)?;
-                            interp_ok(())
                         },
                     }
+
+                    callback.call(this, unblock)
                 }
             ),
         );
     }
 
-    /// Wake up the first thread in the queue that matches any of the bits in the bitset.
-    /// Returns whether anything was woken.
-    fn futex_wake(&mut self, futex_ref: &FutexRef, bitset: u32) -> InterpResult<'tcx, bool> {
+    /// Wake up `count` of the threads in the queue that match any of the bits
+    /// in the bitset. Returns how many threads were woken.
+    fn futex_wake(
+        &mut self,
+        futex_ref: &FutexRef,
+        bitset: u32,
+        count: usize,
+    ) -> InterpResult<'tcx, usize> {
         let this = self.eval_context_mut();
         let mut futex = futex_ref.0.borrow_mut();
         let data_race = &this.machine.data_race;
@@ -800,13 +799,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             data_race.release_clock(&this.machine.threads, |clock| futex.clock.clone_from(clock));
         }
 
-        // Wake up the first thread in the queue that matches any of the bits in the bitset.
-        let Some(i) = futex.waiters.iter().position(|w| w.bitset & bitset != 0) else {
-            return interp_ok(false);
-        };
-        let waiter = futex.waiters.remove(i).unwrap();
+        // Remove `count` of the threads in the queue that match any of the bits in the bitset.
+        // We collect all of them before unblocking because the unblock callback may access the
+        // futex state to retrieve the remaining number of waiters on macOS.
+        let waiters: Vec<_> =
+            futex.waiters.extract_if(.., |w| w.bitset & bitset != 0).take(count).collect();
         drop(futex);
-        this.unblock_thread(waiter.thread, BlockReason::Futex)?;
-        interp_ok(true)
+
+        let woken = waiters.len();
+        for waiter in waiters {
+            this.unblock_thread(waiter.thread, BlockReason::Futex)?;
+        }
+
+        interp_ok(woken)
     }
 }
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 6d22dd8d68d..a8a2491304d 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -1138,7 +1138,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         use rand::Rng as _;
 
         let this = self.eval_context_mut();
-        if this.machine.rng.get_mut().gen_bool(this.machine.preemption_rate) {
+        if this.machine.rng.get_mut().random_bool(this.machine.preemption_rate) {
             this.yield_active_thread();
         }
     }
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index c8f04e25207..36b15dbf623 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -558,15 +558,15 @@ where
 
                 match chars.next() {
                     Some('"') => {
-                        cmd.extend(iter::repeat('\\').take(nslashes * 2 + 1));
+                        cmd.extend(iter::repeat_n('\\', nslashes * 2 + 1));
                         cmd.push('"');
                     }
                     Some(c) => {
-                        cmd.extend(iter::repeat('\\').take(nslashes));
+                        cmd.extend(iter::repeat_n('\\', nslashes));
                         cmd.push(c);
                     }
                     None => {
-                        cmd.extend(iter::repeat('\\').take(nslashes * 2));
+                        cmd.extend(iter::repeat_n('\\', nslashes * 2));
                         break;
                     }
                 }
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index c5538351d7d..a26f12cdfb1 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -421,7 +421,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if this.machine.communicate() {
             // Fill the buffer using the host's rng.
-            getrandom::getrandom(&mut data)
+            getrandom::fill(&mut data)
                 .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?;
         } else {
             let rng = this.machine.rng.get_mut();
@@ -678,6 +678,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )
     }
 
+    /// Helper function used inside shims of foreign functions to check that the target OS
+    /// is one of `target_oses`. It returns an error containing the `name` of the foreign function
+    /// in a message if this is not the case.
+    fn check_target_os(&self, target_oses: &[&str], name: Symbol) -> InterpResult<'tcx> {
+        let target_os = self.eval_context_ref().tcx.sess.target.os.as_ref();
+        if !target_oses.contains(&target_os) {
+            throw_unsup_format!("`{name}` is not supported on {target_os}");
+        }
+        interp_ok(())
+    }
+
     /// Helper function used inside the shims of foreign functions to assert that the target OS
     /// is part of the UNIX family. It panics showing a message with the `name` of the foreign function
     /// if this is not the case.
@@ -991,6 +1002,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         check_arg_count(args)
     }
 
+    /// Check shim for variadic function.
+    /// Returns a tuple that consisting of an array of fixed args, and a slice of varargs.
+    fn check_shim_variadic<'a, const N: usize>(
+        &mut self,
+        abi: &FnAbi<'tcx, Ty<'tcx>>,
+        exp_abi: Conv,
+        link_name: Symbol,
+        args: &'a [OpTy<'tcx>],
+    ) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])>
+    where
+        &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
+    {
+        self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?;
+        check_vargarg_fixed_arg_count(link_name, abi, args)
+    }
+
     /// Mark a machine allocation that was just created as immutable.
     fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx>) {
         let this = self.eval_context_mut();
@@ -1184,8 +1211,10 @@ where
     throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
 }
 
-/// Check that the number of args is at least the minumim what we expect.
-pub fn check_min_arg_count<'a, 'tcx, const N: usize>(
+/// Check that the number of varargs is at least the minimum what we expect.
+/// Fixed args should not be included.
+/// Use `check_vararg_fixed_arg_count` to extract the varargs slice from full function arguments.
+pub fn check_min_vararg_count<'a, 'tcx, const N: usize>(
     name: &'a str,
     args: &'a [OpTy<'tcx>],
 ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
@@ -1193,7 +1222,35 @@ pub fn check_min_arg_count<'a, 'tcx, const N: usize>(
         return interp_ok(ops);
     }
     throw_ub_format!(
-        "incorrect number of arguments for `{name}`: got {}, expected at least {}",
+        "not enough variadic arguments for `{name}`: got {}, expected at least {}",
+        args.len(),
+        N
+    )
+}
+
+/// Check the number of fixed args of a vararg function.
+/// Returns a tuple that consisting of an array of fixed args, and a slice of varargs.
+fn check_vargarg_fixed_arg_count<'a, 'tcx, const N: usize>(
+    link_name: Symbol,
+    abi: &FnAbi<'tcx, Ty<'tcx>>,
+    args: &'a [OpTy<'tcx>],
+) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])> {
+    if !abi.c_variadic {
+        throw_ub_format!("calling a variadic function with a non-variadic caller-side signature");
+    }
+    if abi.fixed_count != u32::try_from(N).unwrap() {
+        throw_ub_format!(
+            "incorrect number of fixed arguments for variadic function `{}`: got {}, expected {N}",
+            link_name.as_str(),
+            abi.fixed_count
+        )
+    }
+    if let Some(args) = args.split_first_chunk() {
+        return interp_ok(args);
+    }
+    throw_ub_format!(
+        "incorrect number of arguments for `{}`: got {}, expected at least {}",
+        link_name.as_str(),
         args.len(),
         N
     )
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 9eebbc5d363..bce78adcaea 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -141,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // FIXME: should we check for validity here? It's tricky because we do not have a
                 // place. Codegen does not seem to set any attributes like `noundef` for intrinsic
                 // calls, so we don't *have* to do anything.
-                let branch: bool = this.machine.rng.get_mut().gen();
+                let branch: bool = this.machine.rng.get_mut().random();
                 this.write_scalar(Scalar::from_bool(branch), dest)?;
             }
 
@@ -289,7 +289,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let a = this.read_scalar(a)?.to_f32()?;
                 let b = this.read_scalar(b)?.to_f32()?;
                 let c = this.read_scalar(c)?.to_f32()?;
-                let fuse: bool = this.machine.rng.get_mut().gen();
+                let fuse: bool = this.machine.rng.get_mut().random();
                 let res = if fuse {
                     // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
                     a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
@@ -304,7 +304,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let a = this.read_scalar(a)?.to_f64()?;
                 let b = this.read_scalar(b)?.to_f64()?;
                 let c = this.read_scalar(c)?.to_f64()?;
-                let fuse: bool = this.machine.rng.get_mut().gen();
+                let fuse: bool = this.machine.rng.get_mut().random();
                 let res = if fuse {
                     // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
                     a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 54bdd3f02c2..45e316b190a 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -304,7 +304,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let c = this.read_scalar(&this.project_index(&c, i)?)?;
                     let dest = this.project_index(&dest, i)?;
 
-                    let fuse: bool = intrinsic_name == "fma" || this.machine.rng.get_mut().gen();
+                    let fuse: bool = intrinsic_name == "fma" || this.machine.rng.get_mut().random();
 
                     // Works for f32 and f64.
                     // FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468.
@@ -639,8 +639,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let (right, right_len) = this.project_to_simd(right)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
 
-                let index =
-                    generic_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch();
+                let index = generic_args[2].expect_const().to_value().valtree.unwrap_branch();
                 let index_len = index.len();
 
                 assert_eq!(left_len, right_len);
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 2955dc38a8c..45054c37c40 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -15,6 +15,8 @@
 #![feature(unqualified_local_imports)]
 #![feature(derive_coerce_pointee)]
 #![feature(arbitrary_self_types)]
+#![feature(unsigned_is_multiple_of)]
+#![feature(extract_if)]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
@@ -36,6 +38,7 @@
     clippy::needless_question_mark,
     clippy::needless_lifetimes,
     clippy::too_long_first_doc_paragraph,
+    // We don't use translatable diagnostics
     rustc::diagnostic_outside_of_impl,
     // We are not implementing queries here so it's fine
     rustc::potential_query_instability,
@@ -168,7 +171,7 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[
     "-Zmir-emit-retag",
     "-Zmir-keep-place-mention",
     "-Zmir-opt-level=0",
-    "-Zmir-enable-passes=-CheckAlignment",
+    "-Zmir-enable-passes=-CheckAlignment,-CheckNull",
     // Deduplicating diagnostics means we miss events when tracking what happens during an
     // execution. Let's not do that.
     "-Zdeduplicate-diagnostics=no",
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 845ba484326..4735db48e81 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -11,6 +11,7 @@ use std::{fmt, process};
 use rand::rngs::StdRng;
 use rand::{Rng, SeedableRng};
 use rustc_abi::{Align, ExternAbi, Size};
+use rustc_apfloat::{Float, FloatConvert};
 use rustc_attr_parsing::InlineAttr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[allow(unused)]
@@ -1111,10 +1112,13 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         // Call the lang item.
         let panic = ecx.tcx.lang_items().get(reason.lang_item()).unwrap();
         let panic = ty::Instance::mono(ecx.tcx.tcx, panic);
-        ecx.call_function(panic, ExternAbi::Rust, &[], None, StackPopCleanup::Goto {
-            ret: None,
-            unwind: mir::UnwindAction::Unreachable,
-        })?;
+        ecx.call_function(
+            panic,
+            ExternAbi::Rust,
+            &[],
+            None,
+            StackPopCleanup::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
+        )?;
         interp_ok(())
     }
 
@@ -1129,20 +1133,24 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     }
 
     #[inline(always)]
-    fn generate_nan<
-        F1: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F2>,
-        F2: rustc_apfloat::Float,
-    >(
+    fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(
         ecx: &InterpCx<'tcx, Self>,
         inputs: &[F1],
     ) -> F2 {
         ecx.generate_nan(inputs)
     }
 
+    #[inline(always)]
+    fn equal_float_min_max<F: Float>(ecx: &MiriInterpCx<'tcx>, a: F, b: F) -> F {
+        ecx.equal_float_min_max(a, b)
+    }
+
+    #[inline(always)]
     fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> {
         interp_ok(ecx.tcx.sess.ub_checks())
     }
 
+    #[inline(always)]
     fn thread_local_static_pointer(
         ecx: &mut MiriInterpCx<'tcx>,
         def_id: DefId,
@@ -1496,7 +1504,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             catch_unwind: None,
             timing,
             is_user_relevant: ecx.machine.is_user_relevant(&frame),
-            salt: ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_ANON_GLOBAL,
+            salt: ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL),
             data_race: ecx.machine.data_race.as_ref().map(|_| data_race::FrameState::default()),
         };
 
@@ -1711,7 +1719,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         if unique {
             CTFE_ALLOC_SALT
         } else {
-            ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_ANON_GLOBAL
+            ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL)
         }
     }
 
diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs
index ed3d2d55678..7117f722fee 100644
--- a/src/tools/miri/src/math.rs
+++ b/src/tools/miri/src/math.rs
@@ -1,9 +1,12 @@
 use rand::Rng as _;
-use rand::distributions::Distribution as _;
 use rustc_apfloat::Float as _;
 use rustc_apfloat::ieee::IeeeFloat;
 
-/// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale).
+/// Disturbes a floating-point result by a relative error in the range (-2^scale, 2^scale).
+///
+/// For a 2^N ULP error, you can use an `err_scale` of `-(F::PRECISION - 1 - N)`.
+/// In other words, a 1 ULP (absolute) error is the same as a `2^-(F::PRECISION-1)` relative error.
+/// (Subtracting 1 compensates for the integer bit.)
 pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
     ecx: &mut crate::MiriInterpCx<'_>,
     val: F,
@@ -11,12 +14,15 @@ pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
 ) -> F {
     let rng = ecx.machine.rng.get_mut();
     // Generate a random integer in the range [0, 2^PREC).
-    let dist = rand::distributions::Uniform::new(0, 1 << F::PRECISION);
-    let err = F::from_u128(dist.sample(rng))
-        .value
-        .scalbn(err_scale.strict_sub(F::PRECISION.try_into().unwrap()));
+    // (When read as binary, the position of the first `1` determines the exponent,
+    // and the remaining bits fill the mantissa. `PREC` is one plus the size of the mantissa,
+    // so this all works out.)
+    let r = F::from_u128(rng.random_range(0..(1 << F::PRECISION))).value;
+    // Multiply this with 2^(scale - PREC). The result is between 0 and
+    // 2^PREC * 2^(scale - PREC) = 2^scale.
+    let err = r.scalbn(err_scale.strict_sub(F::PRECISION.try_into().unwrap()));
     // give it a random sign
-    let err = if rng.gen::<bool>() { -err } else { err };
+    let err = if rng.random() { -err } else { err };
     // multiple the value with (1+err)
     (val * (F::from_u128(1).value + err).value).value
 }
diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs
index 0017a3991b5..c588b6fc7f1 100644
--- a/src/tools/miri/src/operator.rs
+++ b/src/tools/miri/src/operator.rs
@@ -108,11 +108,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Pick one of the NaNs.
         let nan = nans.choose(&mut *rand).unwrap();
         // Non-deterministically flip the sign.
-        if rand.gen() {
+        if rand.random() {
             // This will properly flip even for NaN.
             -nan
         } else {
             nan
         }
     }
+
+    fn equal_float_min_max<F: Float>(&self, a: F, b: F) -> F {
+        let this = self.eval_context_ref();
+        // Return one side non-deterministically.
+        let mut rand = this.machine.rng.borrow_mut();
+        if rand.random() { a } else { b }
+    }
 }
diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs
index 25c0b52d061..323b95d5f5f 100644
--- a/src/tools/miri/src/shims/alloc.rs
+++ b/src/tools/miri/src/shims/alloc.rs
@@ -1,5 +1,3 @@
-use std::iter;
-
 use rustc_abi::{Align, Size};
 use rustc_ast::expand::allocator::AllocatorKind;
 
@@ -80,18 +78,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
     }
 
-    fn malloc(&mut self, size: u64, zero_init: bool) -> InterpResult<'tcx, Pointer> {
+    fn malloc(&mut self, size: u64, init: AllocInit) -> InterpResult<'tcx, Pointer> {
         let this = self.eval_context_mut();
         let align = this.malloc_align(size);
-        let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into())?;
-        if zero_init {
-            // We just allocated this, the access is definitely in-bounds and fits into our address space.
-            this.write_bytes_ptr(
-                ptr.into(),
-                iter::repeat(0u8).take(usize::try_from(size).unwrap()),
-            )
-            .unwrap();
-        }
+        let ptr =
+            this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into(), init)?;
         interp_ok(ptr.into())
     }
 
@@ -102,7 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         size: &OpTy<'tcx>,
     ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
-        let memptr = this.deref_pointer(memptr)?;
+        let memptr = this.deref_pointer_as(memptr, this.machine.layouts.mut_raw_ptr)?;
         let align = this.read_target_usize(align)?;
         let size = this.read_target_usize(size)?;
 
@@ -115,6 +106,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 Size::from_bytes(size),
                 Align::from_bytes(align).unwrap(),
                 MiriMemoryKind::C.into(),
+                AllocInit::Uninit,
             )?;
             this.write_pointer(ptr, &memptr)?;
             interp_ok(Scalar::from_i32(0))
@@ -134,7 +126,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let new_align = this.malloc_align(new_size);
         if this.ptr_is_null(old_ptr)? {
             // Here we must behave like `malloc`.
-            self.malloc(new_size, /*zero_init*/ false)
+            self.malloc(new_size, AllocInit::Uninit)
         } else {
             if new_size == 0 {
                 // C, in their infinite wisdom, made this UB.
@@ -147,6 +139,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(new_size),
                     new_align,
                     MiriMemoryKind::C.into(),
+                    AllocInit::Uninit,
                 )?;
                 interp_ok(new_ptr.into())
             }
@@ -187,6 +180,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(size),
                     Align::from_bytes(align).unwrap(),
                     MiriMemoryKind::C.into(),
+                    AllocInit::Uninit,
                 )?;
                 interp_ok(ptr.into())
             }
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 1622ef280d2..7e667e70a17 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -4,7 +4,6 @@ use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{BytePos, Loc, Symbol, hygiene};
 use rustc_target::callconv::{Conv, FnAbi};
 
-use crate::helpers::check_min_arg_count;
 use crate::*;
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -34,13 +33,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         abi: &FnAbi<'tcx, Ty<'tcx>>,
         link_name: Symbol,
         args: &[OpTy<'tcx>],
-        dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let tcx = this.tcx;
+        let ptr_ty = this.machine.layouts.mut_raw_ptr.ty;
+        let ptr_layout = this.layout_of(ptr_ty)?;
+
+        let [flags, buf] = this.check_shim(abi, Conv::Rust, link_name, args)?;
 
-        let [flags] = check_min_arg_count("miri_get_backtrace", args)?;
         let flags = this.read_scalar(flags)?.to_u64()?;
+        let buf_place = this.deref_pointer_as(buf, ptr_layout)?;
 
         let mut data = Vec::new();
         for frame in this.active_thread_stack().iter().rev() {
@@ -63,44 +64,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             })
             .collect();
 
-        let len: u64 = ptrs.len().try_into().unwrap();
-
-        let ptr_ty = this.machine.layouts.mut_raw_ptr.ty;
-        let array_layout = this.layout_of(Ty::new_array(tcx.tcx, ptr_ty, len)).unwrap();
-
         match flags {
-            // storage for pointers is allocated by miri
-            // deallocating the slice is undefined behavior with a custom global allocator
             0 => {
-                let [_flags] = this.check_shim(abi, Conv::Rust, link_name, args)?;
-
-                let alloc = this.allocate(array_layout, MiriMemoryKind::Rust.into())?;
-
-                // Write pointers into array
-                for (i, ptr) in ptrs.into_iter().enumerate() {
-                    let place = this.project_index(&alloc, i as u64)?;
-
-                    this.write_pointer(ptr, &place)?;
-                }
-
-                this.write_immediate(Immediate::new_slice(alloc.ptr(), len, this), dest)?;
+                throw_unsup_format!("miri_get_backtrace: v0 is not supported any more");
             }
-            // storage for pointers is allocated by the caller
-            1 => {
-                let [_flags, buf] = this.check_shim(abi, Conv::Rust, link_name, args)?;
-
-                let buf_place = this.deref_pointer(buf)?;
-
-                let ptr_layout = this.layout_of(ptr_ty)?;
-
+            1 =>
                 for (i, ptr) in ptrs.into_iter().enumerate() {
                     let offset = ptr_layout.size.checked_mul(i.try_into().unwrap(), this).unwrap();
 
                     let op_place = buf_place.offset(offset, ptr_layout, this)?;
 
                     this.write_pointer(ptr, &op_place)?;
-                }
-            }
+                },
             _ => throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags),
         };
 
diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs
index f0aebfe1693..20dd3c8db2a 100644
--- a/src/tools/miri/src/shims/extern_static.rs
+++ b/src/tools/miri/src/shims/extern_static.rs
@@ -60,10 +60,10 @@ impl<'tcx> MiriMachine<'tcx> {
 
         match ecx.tcx.sess.target.os.as_ref() {
             "linux" => {
-                Self::null_ptr_extern_statics(ecx, &[
-                    "__cxa_thread_atexit_impl",
-                    "__clock_gettime64",
-                ])?;
+                Self::null_ptr_extern_statics(
+                    ecx,
+                    &["__cxa_thread_atexit_impl", "__clock_gettime64"],
+                )?;
                 Self::weak_symbol_extern_statics(ecx, &["getrandom", "statx"])?;
             }
             "freebsd" => {
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs
index 73425eee515..6b4f4cdc922 100644
--- a/src/tools/miri/src/shims/files.rs
+++ b/src/tools/miri/src/shims/files.rs
@@ -1,6 +1,6 @@
 use std::any::Any;
 use std::collections::BTreeMap;
-use std::io::{IsTerminal, Read, SeekFrom, Write};
+use std::io::{IsTerminal, SeekFrom, Write};
 use std::marker::CoercePointee;
 use std::ops::Deref;
 use std::rc::{Rc, Weak};
@@ -140,8 +140,8 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
         _communicate_allowed: bool,
         _ptr: Pointer,
         _len: usize,
-        _dest: &MPlaceTy<'tcx>,
         _ecx: &mut MiriInterpCx<'tcx>,
+        _finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         throw_unsup_format!("cannot read from {}", self.name());
     }
@@ -154,8 +154,8 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
         _communicate_allowed: bool,
         _ptr: Pointer,
         _len: usize,
-        _dest: &MPlaceTy<'tcx>,
         _ecx: &mut MiriInterpCx<'tcx>,
+        _finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         throw_unsup_format!("cannot write to {}", self.name());
     }
@@ -207,19 +207,16 @@ impl FileDescription for io::Stdin {
         communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
-        let mut bytes = vec![0; len];
         if !communicate_allowed {
             // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
             helpers::isolation_abort_error("`read` from stdin")?;
         }
-        let result = Read::read(&mut &*self, &mut bytes);
-        match result {
-            Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest),
-            Err(e) => ecx.set_last_error_and_return(e, dest),
-        }
+
+        let result = ecx.read_from_host(&*self, len, ptr)?;
+        finish.call(ecx, result)
     }
 
     fn is_tty(&self, communicate_allowed: bool) -> bool {
@@ -237,22 +234,19 @@ impl FileDescription for io::Stdout {
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
-        let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
-        // We allow writing to stderr even with isolation enabled.
-        let result = Write::write(&mut &*self, bytes);
+        // We allow writing to stdout even with isolation enabled.
+        let result = ecx.write_to_host(&*self, len, ptr)?;
         // Stdout is buffered, flush to make sure it appears on the
         // screen.  This is the write() syscall of the interpreted
         // program, we want it to correspond to a write() syscall on
         // the host -- there is no good in adding extra buffering
         // here.
         io::stdout().flush().unwrap();
-        match result {
-            Ok(write_size) => ecx.return_write_success(write_size, dest),
-            Err(e) => ecx.set_last_error_and_return(e, dest),
-        }
+
+        finish.call(ecx, result)
     }
 
     fn is_tty(&self, communicate_allowed: bool) -> bool {
@@ -270,17 +264,13 @@ impl FileDescription for io::Stderr {
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
-        let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
         // We allow writing to stderr even with isolation enabled.
+        let result = ecx.write_to_host(&*self, len, ptr)?;
         // No need to flush, stderr is not buffered.
-        let result = Write::write(&mut &*self, bytes);
-        match result {
-            Ok(write_size) => ecx.return_write_success(write_size, dest),
-            Err(e) => ecx.set_last_error_and_return(e, dest),
-        }
+        finish.call(ecx, result)
     }
 
     fn is_tty(&self, communicate_allowed: bool) -> bool {
@@ -302,11 +292,11 @@ impl FileDescription for NullOutput {
         _communicate_allowed: bool,
         _ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         // We just don't write anything, but report to the user that we did.
-        ecx.return_write_success(len, dest)
+        finish.call(ecx, Ok(len))
     }
 }
 
@@ -405,40 +395,41 @@ impl FdTable {
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    /// Helper to implement `FileDescription::read`:
-    /// This is only used when `read` is successful.
-    /// `actual_read_size` should be the return value of some underlying `read` call that used
-    /// `bytes` as its output buffer.
-    /// The length of `bytes` must not exceed either the host's or the target's `isize`.
-    /// `bytes` is written to `buf` and the size is written to `dest`.
-    fn return_read_success(
+    /// Read data from a host `Read` type, store the result into machine memory,
+    /// and return whether that worked.
+    fn read_from_host(
         &mut self,
-        buf: Pointer,
-        bytes: &[u8],
-        actual_read_size: usize,
-        dest: &MPlaceTy<'tcx>,
-    ) -> InterpResult<'tcx> {
+        mut file: impl io::Read,
+        len: usize,
+        ptr: Pointer,
+    ) -> InterpResult<'tcx, Result<usize, IoError>> {
         let this = self.eval_context_mut();
-        // If reading to `bytes` did not fail, we write those bytes to the buffer.
-        // Crucially, if fewer than `bytes.len()` bytes were read, only write
-        // that much into the output buffer!
-        this.write_bytes_ptr(buf, bytes[..actual_read_size].iter().copied())?;
 
-        // The actual read size is always less than what got originally requested so this cannot fail.
-        this.write_int(u64::try_from(actual_read_size).unwrap(), dest)?;
-        interp_ok(())
+        let mut bytes = vec![0; len];
+        let result = file.read(&mut bytes);
+        match result {
+            Ok(read_size) => {
+                // If reading to `bytes` did not fail, we write those bytes to the buffer.
+                // Crucially, if fewer than `bytes.len()` bytes were read, only write
+                // that much into the output buffer!
+                this.write_bytes_ptr(ptr, bytes[..read_size].iter().copied())?;
+                interp_ok(Ok(read_size))
+            }
+            Err(e) => interp_ok(Err(IoError::HostError(e))),
+        }
     }
 
-    /// Helper to implement `FileDescription::write`:
-    /// This function is only used when `write` is successful, and writes `actual_write_size` to `dest`
-    fn return_write_success(
+    /// Write data to a host `Write` type, withthe bytes taken from machine memory.
+    fn write_to_host(
         &mut self,
-        actual_write_size: usize,
-        dest: &MPlaceTy<'tcx>,
-    ) -> InterpResult<'tcx> {
+        mut file: impl io::Write,
+        len: usize,
+        ptr: Pointer,
+    ) -> InterpResult<'tcx, Result<usize, IoError>> {
         let this = self.eval_context_mut();
-        // The actual write size is always less than what got originally requested so this cannot fail.
-        this.write_int(u64::try_from(actual_write_size).unwrap(), dest)?;
-        interp_ok(())
+
+        let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
+        let result = file.write(bytes);
+        interp_ok(result.map_err(IoError::HostError))
     }
 }
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 6c8ccc83985..97bfb04f1f4 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -1,6 +1,5 @@
 use std::collections::hash_map::Entry;
 use std::io::Write;
-use std::iter;
 use std::path::Path;
 
 use rustc_abi::{Align, AlignFromBytesError, Size};
@@ -9,6 +8,7 @@ use rustc_ast::expand::allocator::alloc_error_handler_name;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::interpret::AllocInit;
 use rustc_middle::ty::Ty;
 use rustc_middle::{mir, ty};
 use rustc_span::Symbol;
@@ -357,7 +357,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Obtains a Miri backtrace. See the README for details.
             "miri_get_backtrace" => {
                 // `check_shim` happens inside `handle_miri_get_backtrace`.
-                this.handle_miri_get_backtrace(abi, link_name, args, dest)?;
+                this.handle_miri_get_backtrace(abi, link_name, args)?;
             }
             // Resolves a Miri backtrace frame. See the README for details.
             "miri_resolve_frame" => {
@@ -442,7 +442,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let size = this.read_target_usize(size)?;
                 if size <= this.max_size_of_val().bytes() {
-                    let res = this.malloc(size, /*zero_init:*/ false)?;
+                    let res = this.malloc(size, AllocInit::Uninit)?;
                     this.write_pointer(res, dest)?;
                 } else {
                     // If this does not fit in an isize, return null and, on Unix, set errno.
@@ -457,7 +457,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let items = this.read_target_usize(items)?;
                 let elem_size = this.read_target_usize(elem_size)?;
                 if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) {
-                    let res = this.malloc(size.bytes(), /*zero_init:*/ true)?;
+                    let res = this.malloc(size.bytes(), AllocInit::Zero)?;
                     this.write_pointer(res, dest)?;
                 } else {
                     // On size overflow, return null and, on Unix, set errno.
@@ -509,6 +509,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         Size::from_bytes(size),
                         Align::from_bytes(align).unwrap(),
                         memory_kind.into(),
+                        AllocInit::Uninit,
                     )?;
 
                     ecx.write_pointer(ptr, dest)
@@ -537,14 +538,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         Size::from_bytes(size),
                         Align::from_bytes(align).unwrap(),
                         MiriMemoryKind::Rust.into(),
+                        AllocInit::Zero,
                     )?;
-
-                    // We just allocated this, the access is definitely in-bounds.
-                    this.write_bytes_ptr(
-                        ptr.into(),
-                        iter::repeat(0u8).take(usize::try_from(size).unwrap()),
-                    )
-                    .unwrap();
                     this.write_pointer(ptr, dest)
                 });
             }
@@ -604,6 +599,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         Size::from_bytes(new_size),
                         align,
                         MiriMemoryKind::Rust.into(),
+                        AllocInit::Uninit,
                     )?;
                     this.write_pointer(new_ptr, dest)
                 });
@@ -865,7 +861,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "lgammaf_r" => {
                 let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let x = this.read_scalar(x)?.to_f32()?;
-                let signp = this.deref_pointer(signp)?;
+                let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
 
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let (res, sign) = x.to_host().ln_gamma();
@@ -876,7 +872,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "lgamma_r" => {
                 let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let x = this.read_scalar(x)?.to_f64()?;
-                let signp = this.deref_pointer(signp)?;
+                let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
 
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let (res, sign) = x.to_host().ln_gamma();
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 93479540009..83f331bb173 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -247,10 +247,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Call the lang item associated with this message.
                 let fn_item = this.tcx.require_lang_item(msg.panic_function(), None);
                 let instance = ty::Instance::mono(this.tcx.tcx, fn_item);
-                this.call_function(instance, ExternAbi::Rust, &[], None, StackPopCleanup::Goto {
-                    ret: None,
-                    unwind,
-                })?;
+                this.call_function(
+                    instance,
+                    ExternAbi::Rust,
+                    &[],
+                    None,
+                    StackPopCleanup::Goto { ret: None, unwind },
+                )?;
             }
         }
         interp_ok(())
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index d6c77d9c4d9..64b3ce6b4e4 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -132,16 +132,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.assert_target_os_is_unix("localtime_r");
         this.check_no_isolation("`localtime_r`")?;
 
-        let timep = this.deref_pointer(timep)?;
+        let time_layout = this.libc_ty_layout("time_t");
+        let timep = this.deref_pointer_as(timep, time_layout)?;
         let result = this.deref_pointer_as(result_op, this.libc_ty_layout("tm"))?;
 
         // The input "represents the number of seconds elapsed since the Epoch,
         // 1970-01-01 00:00:00 +0000 (UTC)".
-        let sec_since_epoch: i64 = this
-            .read_scalar(&timep)?
-            .to_int(this.libc_ty_layout("time_t").size)?
-            .try_into()
-            .unwrap();
+        let sec_since_epoch: i64 =
+            this.read_scalar(&timep)?.to_int(time_layout.size)?.try_into().unwrap();
         let dt_utc: DateTime<Utc> =
             DateTime::from_timestamp(sec_since_epoch, 0).expect("Invalid timestamp");
 
@@ -254,7 +252,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let qpc = i64::try_from(duration.as_nanos()).map_err(|_| {
             err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported")
         })?;
-        this.write_scalar(Scalar::from_i64(qpc), &this.deref_pointer(lpPerformanceCount_op)?)?;
+        this.write_scalar(
+            Scalar::from_i64(qpc),
+            &this.deref_pointer_as(lpPerformanceCount_op, this.machine.layouts.i64)?,
+        )?;
         interp_ok(Scalar::from_i32(-1)) // return non-zero on success
     }
 
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
index 8d5d4a52b6e..c7e2c4d507b 100644
--- a/src/tools/miri/src/shims/unix/android/thread.rs
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -3,7 +3,7 @@ use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
 use rustc_target::callconv::{Conv, FnAbi};
 
-use crate::helpers::check_min_arg_count;
+use crate::helpers::check_min_vararg_count;
 use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult};
 use crate::*;
 
@@ -16,18 +16,15 @@ pub fn prctl<'tcx>(
     args: &[OpTy<'tcx>],
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx> {
-    // We do not use `check_shim` here because `prctl` is variadic. The argument
-    // count is checked bellow.
-    ecx.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
+    let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?;
 
     // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
     let pr_set_name = 15;
     let pr_get_name = 16;
 
-    let [op] = check_min_arg_count("prctl", args)?;
     let res = match ecx.read_scalar(op)?.to_i32()? {
         op if op == pr_set_name => {
-            let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?;
+            let [name] = check_min_vararg_count("prctl(PR_SET_NAME, ...)", varargs)?;
             let name = ecx.read_scalar(name)?;
             let thread = ecx.pthread_self()?;
             // The Linux kernel silently truncates long names.
@@ -38,7 +35,7 @@ pub fn prctl<'tcx>(
             Scalar::from_u32(0)
         }
         op if op == pr_get_name => {
-            let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?;
+            let [name] = check_min_vararg_count("prctl(PR_GET_NAME, ...)", varargs)?;
             let name = ecx.read_scalar(name)?;
             let thread = ecx.pthread_self()?;
             let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, ecx);
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 0b59490308b..3f85b9ae9bd 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -6,7 +6,7 @@ use std::io::ErrorKind;
 
 use rustc_abi::Size;
 
-use crate::helpers::check_min_arg_count;
+use crate::helpers::check_min_vararg_count;
 use crate::shims::files::FileDescription;
 use crate::shims::unix::linux_like::epoll::EpollReadyEvents;
 use crate::shims::unix::*;
@@ -30,8 +30,8 @@ pub trait UnixFileDescription: FileDescription {
         _offset: u64,
         _ptr: Pointer,
         _len: usize,
-        _dest: &MPlaceTy<'tcx>,
         _ecx: &mut MiriInterpCx<'tcx>,
+        _finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         throw_unsup_format!("cannot pread from {}", self.name());
     }
@@ -46,8 +46,8 @@ pub trait UnixFileDescription: FileDescription {
         _ptr: Pointer,
         _len: usize,
         _offset: u64,
-        _dest: &MPlaceTy<'tcx>,
         _ecx: &mut MiriInterpCx<'tcx>,
+        _finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         throw_unsup_format!("cannot pwrite to {}", self.name());
     }
@@ -127,11 +127,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
+    fn fcntl(
+        &mut self,
+        fd_num: &OpTy<'tcx>,
+        cmd: &OpTy<'tcx>,
+        varargs: &[OpTy<'tcx>],
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let [fd_num, cmd] = check_min_arg_count("fcntl", args)?;
-
         let fd_num = this.read_scalar(fd_num)?.to_i32()?;
         let cmd = this.read_scalar(cmd)?.to_i32()?;
 
@@ -163,7 +166,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     "fcntl(fd, F_DUPFD_CLOEXEC, ...)"
                 };
 
-                let [_, _, start] = check_min_arg_count(cmd_name, args)?;
+                let [start] = check_min_vararg_count(cmd_name, varargs)?;
                 let start = this.read_scalar(start)?.to_i32()?;
 
                 if let Some(fd) = this.machine.fds.get(fd_num) {
@@ -233,7 +236,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let count = usize::try_from(count).unwrap(); // now it fits in a `usize`
         let communicate = this.machine.communicate();
 
-        // We temporarily dup the FD to be able to retain mutable access to `this`.
+        // Get the FD.
         let Some(fd) = this.machine.fds.get(fd_num) else {
             trace!("read: FD not found");
             return this.set_last_error_and_return(LibcError("EBADF"), dest);
@@ -244,13 +247,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // because it was a target's `usize`. Also we are sure that its smaller than
         // `usize::MAX` because it is bounded by the host's `isize`.
 
+        let finish = {
+            let dest = dest.clone();
+            callback!(
+                @capture<'tcx> {
+                    count: usize,
+                    dest: MPlaceTy<'tcx>,
+                }
+                |this, result: Result<usize, IoError>| {
+                    match result {
+                        Ok(read_size) => {
+                            assert!(read_size <= count);
+                            // This must fit since `count` fits.
+                            this.write_int(u64::try_from(read_size).unwrap(), &dest)
+                        }
+                        Err(e) => {
+                            this.set_last_error_and_return(e, &dest)
+                        }
+                }}
+            )
+        };
         match offset {
-            None => fd.read(communicate, buf, count, dest, this)?,
+            None => fd.read(communicate, buf, count, this, finish)?,
             Some(offset) => {
                 let Ok(offset) = u64::try_from(offset) else {
                     return this.set_last_error_and_return(LibcError("EINVAL"), dest);
                 };
-                fd.as_unix().pread(communicate, offset, buf, count, dest, this)?
+                fd.as_unix().pread(communicate, offset, buf, count, this, finish)?
             }
         };
         interp_ok(())
@@ -284,13 +307,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
 
+        let finish = {
+            let dest = dest.clone();
+            callback!(
+                @capture<'tcx> {
+                    count: usize,
+                    dest: MPlaceTy<'tcx>,
+                }
+                |this, result: Result<usize, IoError>| {
+                    match result {
+                        Ok(write_size) => {
+                            assert!(write_size <= count);
+                            // This must fit since `count` fits.
+                            this.write_int(u64::try_from(write_size).unwrap(), &dest)
+                        }
+                        Err(e) => {
+                            this.set_last_error_and_return(e, &dest)
+                        }
+                }}
+            )
+        };
         match offset {
-            None => fd.write(communicate, buf, count, dest, this)?,
+            None => fd.write(communicate, buf, count, this, finish)?,
             Some(offset) => {
                 let Ok(offset) = u64::try_from(offset) else {
                     return this.set_last_error_and_return(LibcError("EINVAL"), dest);
                 };
-                fd.as_unix().pwrite(communicate, buf, count, offset, dest, this)?
+                fd.as_unix().pwrite(communicate, buf, count, offset, this, finish)?
             }
         };
         interp_ok(())
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 3353cf2cc59..d459ec7cb77 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -205,10 +205,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
             "fcntl" => {
-                // `fcntl` is variadic. The argument count is checked based on the first argument
-                // in `this.fcntl()`, so we do not use `check_shim` here.
-                this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
-                let result = this.fcntl(args)?;
+                let ([fd_num, cmd], varargs) =
+                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                let result = this.fcntl(fd_num, cmd, varargs)?;
                 this.write_scalar(result, dest)?;
             }
             "dup" => {
@@ -236,8 +235,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "open" | "open64" => {
                 // `open` is variadic, the third argument is only present when the second argument
                 // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
-                this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
-                let result = this.open(args)?;
+                let ([path_raw, flag], varargs) =
+                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                let result = this.open(path_raw, flag, varargs)?;
                 this.write_scalar(result, dest)?;
             }
             "unlink" => {
@@ -354,10 +354,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "pipe2" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "solaris" | "illumos")
-                {
-                    throw_unsup_format!("`pipe2` is not supported on {}", this.tcx.sess.target.os);
-                }
+                this.check_target_os(&["linux", "freebsd", "solaris", "illumos"], link_name)?;
                 let [pipefd, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pipe2(pipefd, Some(flags))?;
                 this.write_scalar(result, dest)?;
@@ -402,12 +399,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             "reallocarray" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") {
-                    throw_unsup_format!(
-                        "`reallocarray` is not supported on {}",
-                        this.tcx.sess.target.os
-                    );
-                }
+                this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
                 let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let nmemb = this.read_target_usize(nmemb)?;
@@ -656,13 +648,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "sched_getaffinity" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") {
-                    throw_unsup_format!(
-                        "`sched_getaffinity` is not supported on {}",
-                        this.tcx.sess.target.os
-                    );
-                }
-
+                this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
                 let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let pid = this.read_scalar(pid)?.to_u32()?;
                 let cpusetsize = this.read_target_usize(cpusetsize)?;
@@ -699,13 +685,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "sched_setaffinity" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") {
-                    throw_unsup_format!(
-                        "`sched_setaffinity` is not supported on {}",
-                        this.tcx.sess.target.os
-                    );
-                }
-
+                this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
                 let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let pid = this.read_scalar(pid)?.to_u32()?;
                 let cpusetsize = this.read_target_usize(cpusetsize)?;
@@ -761,16 +741,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "getentropy" => {
                 // This function is non-standard but exists with the same signature and behavior on
                 // Linux, macOS, FreeBSD and Solaris/Illumos.
-                if !matches!(
-                    &*this.tcx.sess.target.os,
-                    "linux" | "macos" | "freebsd" | "illumos" | "solaris" | "android"
-                ) {
-                    throw_unsup_format!(
-                        "`getentropy` is not supported on {}",
-                        this.tcx.sess.target.os
-                    );
-                }
-
+                this.check_target_os(
+                    &["linux", "macos", "freebsd", "illumos", "solaris", "android"],
+                    link_name,
+                )?;
                 let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let buf = this.read_pointer(buf)?;
                 let bufsize = this.read_target_usize(bufsize)?;
@@ -797,15 +771,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "getrandom" => {
                 // This function is non-standard but exists with the same signature and behavior on
                 // Linux, FreeBSD and Solaris/Illumos.
-                if !matches!(
-                    &*this.tcx.sess.target.os,
-                    "linux" | "freebsd" | "illumos" | "solaris" | "android"
-                ) {
-                    throw_unsup_format!(
-                        "`getrandom` is not supported on {}",
-                        this.tcx.sess.target.os
-                    );
-                }
+                this.check_target_os(
+                    &["linux", "freebsd", "illumos", "solaris", "android"],
+                    link_name,
+                )?;
                 let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
@@ -817,12 +786,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "arc4random_buf" => {
                 // This function is non-standard but exists with the same signature and
                 // same behavior (eg never fails) on FreeBSD and Solaris/Illumos.
-                if !matches!(&*this.tcx.sess.target.os, "freebsd" | "illumos" | "solaris") {
-                    throw_unsup_format!(
-                        "`arc4random_buf` is not supported on {}",
-                        this.tcx.sess.target.os
-                    );
-                }
+                this.check_target_os(&["freebsd", "illumos", "solaris"], link_name)?;
                 let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
@@ -842,15 +806,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // For arm32 they did something custom, but similar enough that the same
                 // `_Unwind_RaiseException` impl in miri should work:
                 // https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst
-                if !matches!(
-                    &*this.tcx.sess.target.os,
-                    "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos"
-                ) {
-                    throw_unsup_format!(
-                        "`_Unwind_RaiseException` is not supported on {}",
-                        this.tcx.sess.target.os
-                    );
-                }
+                this.check_target_os(
+                    &["linux", "freebsd", "illumos", "solaris", "android", "macos"],
+                    link_name,
+                )?;
                 // This function looks and behaves excatly like miri_start_unwind.
                 let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
@@ -866,8 +825,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // These shims are enabled only when the caller is in the standard library.
             "pthread_attr_getguardsize" if this.frame_in_std() => {
                 let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let guard_size = this.deref_pointer(guard_size)?;
                 let guard_size_layout = this.libc_ty_layout("size_t");
+                let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
                 this.write_scalar(
                     Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
                     &guard_size,
@@ -893,8 +852,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.check_shim(abi, Conv::C, link_name, args)?;
                 let _attr_place =
                     this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
-                let addr_place = this.deref_pointer(addr_place)?;
-                let size_place = this.deref_pointer(size_place)?;
+                let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?;
+                let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?;
 
                 this.write_scalar(
                     Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
@@ -928,7 +887,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
                 let buf = this.read_pointer(buf)?;
                 let buflen = this.read_target_usize(buflen)?;
-                let result = this.deref_pointer(result)?;
+                let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?;
 
                 // Must be for "us".
                 if uid != UID {
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 03dbd931329..08d06fe5d4c 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -60,17 +60,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // since freebsd 12 the former form can be expected.
             "stat" | "stat@FBSD_1.0" => {
                 let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.macos_fbsd_solaris_stat(path, buf)?;
+                let result = this.macos_fbsd_solarish_stat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "lstat" | "lstat@FBSD_1.0" => {
                 let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.macos_fbsd_solaris_lstat(path, buf)?;
+                let result = this.macos_fbsd_solarish_lstat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "fstat" | "fstat@FBSD_1.0" => {
                 let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.macos_fbsd_solaris_fstat(fd, buf)?;
+                let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "readdir_r" | "readdir_r@FBSD_1.0" => {
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 25594b78031..c7399b00d3f 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -13,7 +13,7 @@ use rustc_abi::Size;
 use rustc_data_structures::fx::FxHashMap;
 
 use self::shims::time::system_time_to_duration;
-use crate::helpers::check_min_arg_count;
+use crate::helpers::check_min_vararg_count;
 use crate::shims::files::{EvalContextExt as _, FileDescription, FileDescriptionRef};
 use crate::shims::os_str::bytes_to_os_str;
 use crate::shims::unix::fd::{FlockOp, UnixFileDescription};
@@ -35,16 +35,13 @@ impl FileDescription for FileHandle {
         communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
-        let mut bytes = vec![0; len];
-        let result = (&mut &self.file).read(&mut bytes);
-        match result {
-            Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest),
-            Err(e) => ecx.set_last_error_and_return(e, dest),
-        }
+
+        let result = ecx.read_from_host(&self.file, len, ptr)?;
+        finish.call(ecx, result)
     }
 
     fn write<'tcx>(
@@ -52,16 +49,13 @@ impl FileDescription for FileHandle {
         communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
-        let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
-        let result = (&mut &self.file).write(bytes);
-        match result {
-            Ok(write_size) => ecx.return_write_success(write_size, dest),
-            Err(e) => ecx.set_last_error_and_return(e, dest),
-        }
+
+        let result = ecx.write_to_host(&self.file, len, ptr)?;
+        finish.call(ecx, result)
     }
 
     fn seek<'tcx>(
@@ -119,8 +113,8 @@ impl UnixFileDescription for FileHandle {
         offset: u64,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
         let mut bytes = vec![0; len];
@@ -137,11 +131,17 @@ impl UnixFileDescription for FileHandle {
                 .expect("failed to restore file position, this shouldn't be possible");
             res
         };
-        let result = f();
-        match result {
-            Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest),
-            Err(e) => ecx.set_last_error_and_return(e, dest),
-        }
+        let result = match f() {
+            Ok(read_size) => {
+                // If reading to `bytes` did not fail, we write those bytes to the buffer.
+                // Crucially, if fewer than `bytes.len()` bytes were read, only write
+                // that much into the output buffer!
+                ecx.write_bytes_ptr(ptr, bytes[..read_size].iter().copied())?;
+                Ok(read_size)
+            }
+            Err(e) => Err(IoError::HostError(e)),
+        };
+        finish.call(ecx, result)
     }
 
     fn pwrite<'tcx>(
@@ -150,8 +150,8 @@ impl UnixFileDescription for FileHandle {
         ptr: Pointer,
         len: usize,
         offset: u64,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
         // Emulates pwrite using seek + write + seek to restore cursor position.
@@ -169,10 +169,7 @@ impl UnixFileDescription for FileHandle {
             res
         };
         let result = f();
-        match result {
-            Ok(write_size) => ecx.return_write_success(write_size, dest),
-            Err(e) => ecx.set_last_error_and_return(e, dest),
-        }
+        finish.call(ecx, result.map_err(IoError::HostError))
     }
 
     fn flock<'tcx>(
@@ -273,7 +270,7 @@ impl UnixFileDescription for FileHandle {
 
 impl<'tcx> EvalContextExtPrivate<'tcx> for crate::MiriInterpCx<'tcx> {}
 trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    fn macos_fbsd_solaris_write_buf(
+    fn macos_fbsd_solarish_write_stat_buf(
         &mut self,
         metadata: FileMetadata,
         buf_op: &OpTy<'tcx>,
@@ -321,9 +318,9 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
 
         if matches!(&*this.tcx.sess.target.os, "solaris" | "illumos") {
-            // FIXME: write st_fstype field once libc is updated.
-            // https://github.com/rust-lang/libc/pull/4145
-            //this.write_int_fields_named(&[("st_fstype", 0)], &buf)?;
+            let st_fstype = this.project_field_named(&buf, "st_fstype")?;
+            // This is an array; write 0 into first element so that it encodes the empty string.
+            this.write_int(0, &this.project_index(&st_fstype, 0)?)?;
         }
 
         interp_ok(0)
@@ -452,9 +449,12 @@ fn maybe_sync_file(
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
-        let [path_raw, flag] = check_min_arg_count("open", args)?;
-
+    fn open(
+        &mut self,
+        path_raw: &OpTy<'tcx>,
+        flag: &OpTy<'tcx>,
+        varargs: &[OpTy<'tcx>],
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let path_raw = this.read_pointer(path_raw)?;
@@ -507,7 +507,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Get the mode.  On macOS, the argument type `mode_t` is actually `u16`, but
             // C integer promotion rules mean that on the ABI level, it gets passed as `u32`
             // (see https://github.com/rust-lang/rust/issues/71915).
-            let [_, _, mode] = check_min_arg_count("open(pathname, O_CREAT, ...)", args)?;
+            let [mode] = check_min_vararg_count("open(pathname, O_CREAT, ...)", varargs)?;
             let mode = this.read_scalar(mode)?.to_u32()?;
 
             #[cfg(unix)]
@@ -668,7 +668,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    fn macos_fbsd_solaris_stat(
+    fn macos_fbsd_solarish_stat(
         &mut self,
         path_op: &OpTy<'tcx>,
         buf_op: &OpTy<'tcx>,
@@ -694,11 +694,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Err(err) => return this.set_last_error_and_return_i32(err),
         };
 
-        interp_ok(Scalar::from_i32(this.macos_fbsd_solaris_write_buf(metadata, buf_op)?))
+        interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?))
     }
 
     // `lstat` is used to get symlink metadata.
-    fn macos_fbsd_solaris_lstat(
+    fn macos_fbsd_solarish_lstat(
         &mut self,
         path_op: &OpTy<'tcx>,
         buf_op: &OpTy<'tcx>,
@@ -726,10 +726,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Err(err) => return this.set_last_error_and_return_i32(err),
         };
 
-        interp_ok(Scalar::from_i32(this.macos_fbsd_solaris_write_buf(metadata, buf_op)?))
+        interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?))
     }
 
-    fn macos_fbsd_solaris_fstat(
+    fn macos_fbsd_solarish_fstat(
         &mut self,
         fd_op: &OpTy<'tcx>,
         buf_op: &OpTy<'tcx>,
@@ -756,7 +756,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Ok(metadata) => metadata,
             Err(err) => return this.set_last_error_and_return_i32(err),
         };
-        interp_ok(Scalar::from_i32(this.macos_fbsd_solaris_write_buf(metadata, buf_op)?))
+        interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?))
     }
 
     fn linux_statx(
@@ -1109,6 +1109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(size),
                     dirent_layout.align.abi,
                     MiriMemoryKind::Runtime.into(),
+                    AllocInit::Uninit,
                 )?;
                 let entry: Pointer = entry.into();
 
@@ -1168,6 +1169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
 
         let dirp = this.read_target_usize(dirp_op)?;
+        let result_place = this.deref_pointer_as(result_op, this.machine.layouts.mut_raw_ptr)?;
 
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
@@ -1253,15 +1255,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     }
                     _ => unreachable!(),
                 }
-
-                let result_place = this.deref_pointer(result_op)?;
                 this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
 
                 Scalar::from_i32(0)
             }
             None => {
                 // end of stream: return 0, assign *result=NULL
-                this.write_null(&this.deref_pointer(result_op)?)?;
+                this.write_null(&result_place)?;
                 Scalar::from_i32(0)
             }
             Some(Err(e)) => {
@@ -1547,7 +1547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
     }
     fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
-        use rand::seq::SliceRandom;
+        use rand::seq::IndexedRandom;
 
         // POSIX defines the template string.
         const TEMPFILE_TEMPLATE_STR: &str = "XXXXXX";
diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs
index 8e796d5dce5..8e5a3021b1c 100644
--- a/src/tools/miri/src/shims/unix/linux/mem.rs
+++ b/src/tools/miri/src/shims/unix/linux/mem.rs
@@ -49,16 +49,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Size::from_bytes(new_size),
             align,
             MiriMemoryKind::Mmap.into(),
+            AllocInit::Zero,
         )?;
-        if let Some(increase) = new_size.checked_sub(old_size) {
-            // We just allocated this, the access is definitely in-bounds and fits into our address space.
-            // mmap guarantees new mappings are zero-init.
-            this.write_bytes_ptr(
-                ptr.wrapping_offset(Size::from_bytes(old_size), this).into(),
-                std::iter::repeat(0u8).take(usize::try_from(increase).unwrap()),
-            )
-            .unwrap();
-        }
 
         interp_ok(Scalar::from_pointer(ptr, this))
     }
diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
index 4b76bbb2b4d..936d436bd82 100644
--- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
@@ -51,20 +51,20 @@ impl FileDescription for EventFd {
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         // We're treating the buffer as a `u64`.
         let ty = ecx.machine.layouts.u64;
         // Check the size of slice, and return error only if the size of the slice < 8.
         if len < ty.size.bytes_usize() {
-            return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
+            return finish.call(ecx, Err(ErrorKind::InvalidInput.into()));
         }
 
         // Turn the pointer into a place at the right type.
         let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
 
-        eventfd_read(buf_place, dest, self, ecx)
+        eventfd_read(buf_place, self, ecx, finish)
     }
 
     /// A write call adds the 8-byte integer value supplied in
@@ -84,20 +84,20 @@ impl FileDescription for EventFd {
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
         // We're treating the buffer as a `u64`.
         let ty = ecx.machine.layouts.u64;
         // Check the size of slice, and return error only if the size of the slice < 8.
         if len < ty.layout.size.bytes_usize() {
-            return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
+            return finish.call(ecx, Err(ErrorKind::InvalidInput.into()));
         }
 
         // Turn the pointer into a place at the right type.
         let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
 
-        eventfd_write(buf_place, dest, self, ecx)
+        eventfd_write(buf_place, self, ecx, finish)
     }
 
     fn as_unix(&self) -> &dyn UnixFileDescription {
@@ -183,15 +183,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 /// else just add the user-supplied value to current counter.
 fn eventfd_write<'tcx>(
     buf_place: MPlaceTy<'tcx>,
-    dest: &MPlaceTy<'tcx>,
     eventfd: FileDescriptionRef<EventFd>,
     ecx: &mut MiriInterpCx<'tcx>,
+    finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
 ) -> InterpResult<'tcx> {
     // Figure out which value we should add.
     let num = ecx.read_scalar(&buf_place)?.to_u64()?;
     // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
     if num == u64::MAX {
-        return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
+        return finish.call(ecx, Err(ErrorKind::InvalidInput.into()));
     }
 
     match eventfd.counter.get().checked_add(num) {
@@ -219,16 +219,14 @@ fn eventfd_write<'tcx>(
             ecx.check_and_update_readiness(eventfd)?;
 
             // Return how many bytes we consumed from the user-provided buffer.
-            return ecx.write_int(buf_place.layout.size.bytes(), dest);
+            return finish.call(ecx, Ok(buf_place.layout.size.bytes_usize()));
         }
         None | Some(u64::MAX) => {
             // We can't update the state, so we have to block.
             if eventfd.is_nonblock {
-                return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
+                return finish.call(ecx, Err(ErrorKind::WouldBlock.into()));
             }
 
-            let dest = dest.clone();
-
             eventfd.blocked_write_tid.borrow_mut().push(ecx.active_thread());
 
             let weak_eventfd = FileDescriptionRef::downgrade(&eventfd);
@@ -239,7 +237,7 @@ fn eventfd_write<'tcx>(
                     @capture<'tcx> {
                         num: u64,
                         buf_place: MPlaceTy<'tcx>,
-                        dest: MPlaceTy<'tcx>,
+                        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
                         weak_eventfd: WeakFileDescriptionRef<EventFd>,
                     }
                     |this, unblock: UnblockKind| {
@@ -247,7 +245,7 @@ fn eventfd_write<'tcx>(
                         // When we get unblocked, try again. We know the ref is still valid,
                         // otherwise there couldn't be a `write` that unblocks us.
                         let eventfd_ref = weak_eventfd.upgrade().unwrap();
-                        eventfd_write(buf_place, &dest, eventfd_ref, this)
+                        eventfd_write(buf_place, eventfd_ref, this, finish)
                     }
                 ),
             );
@@ -260,9 +258,9 @@ fn eventfd_write<'tcx>(
 /// else just return the current counter value to the caller and set the counter to 0.
 fn eventfd_read<'tcx>(
     buf_place: MPlaceTy<'tcx>,
-    dest: &MPlaceTy<'tcx>,
     eventfd: FileDescriptionRef<EventFd>,
     ecx: &mut MiriInterpCx<'tcx>,
+    finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
 ) -> InterpResult<'tcx> {
     // Set counter to 0, get old value.
     let counter = eventfd.counter.replace(0);
@@ -270,9 +268,8 @@ fn eventfd_read<'tcx>(
     // Block when counter == 0.
     if counter == 0 {
         if eventfd.is_nonblock {
-            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
+            return finish.call(ecx, Err(ErrorKind::WouldBlock.into()));
         }
-        let dest = dest.clone();
 
         eventfd.blocked_read_tid.borrow_mut().push(ecx.active_thread());
 
@@ -283,7 +280,7 @@ fn eventfd_read<'tcx>(
             callback!(
                 @capture<'tcx> {
                     buf_place: MPlaceTy<'tcx>,
-                    dest: MPlaceTy<'tcx>,
+                    finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
                     weak_eventfd: WeakFileDescriptionRef<EventFd>,
                 }
                 |this, unblock: UnblockKind| {
@@ -291,7 +288,7 @@ fn eventfd_read<'tcx>(
                     // When we get unblocked, try again. We know the ref is still valid,
                     // otherwise there couldn't be a `write` that unblocks us.
                     let eventfd_ref = weak_eventfd.upgrade().unwrap();
-                    eventfd_read(buf_place, &dest, eventfd_ref, this)
+                    eventfd_read(buf_place, eventfd_ref, this, finish)
                 }
             ),
         );
@@ -317,7 +314,7 @@ fn eventfd_read<'tcx>(
         ecx.check_and_update_readiness(eventfd)?;
 
         // Tell userspace how many bytes we put into the buffer.
-        return ecx.write_int(buf_place.layout.size.bytes(), dest);
+        return finish.call(ecx, Ok(buf_place.layout.size.bytes_usize()));
     }
     interp_ok(())
 }
diff --git a/src/tools/miri/src/shims/unix/linux_like/sync.rs b/src/tools/miri/src/shims/unix/linux_like/sync.rs
index 51124fb2a00..280bee4800f 100644
--- a/src/tools/miri/src/shims/unix/linux_like/sync.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/sync.rs
@@ -1,5 +1,5 @@
 use crate::concurrency::sync::FutexRef;
-use crate::helpers::check_min_arg_count;
+use crate::helpers::check_min_vararg_count;
 use crate::*;
 
 struct LinuxFutex {
@@ -10,7 +10,7 @@ struct LinuxFutex {
 /// `args` is the arguments *including* the syscall number.
 pub fn futex<'tcx>(
     ecx: &mut MiriInterpCx<'tcx>,
-    args: &[OpTy<'tcx>],
+    varargs: &[OpTy<'tcx>],
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx> {
     // The amount of arguments used depends on the type of futex operation.
@@ -21,7 +21,7 @@ pub fn futex<'tcx>(
     // may or may not be left out from the `syscall()` call.
     // Therefore we don't use `check_arg_count` here, but only check for the
     // number of arguments to fall within a range.
-    let [_, addr, op, val] = check_min_arg_count("`syscall(SYS_futex, ...)`", args)?;
+    let [addr, op, val] = check_min_vararg_count("`syscall(SYS_futex, ...)`", varargs)?;
 
     // The first three arguments (after the syscall number itself) are the same to all futex operations:
     //     (int *addr, int op, int val).
@@ -55,14 +55,16 @@ pub fn futex<'tcx>(
             let wait_bitset = op & !futex_realtime == futex_wait_bitset;
 
             let (timeout, bitset) = if wait_bitset {
-                let [_, _, _, _, timeout, uaddr2, bitset] =
-                    check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT_BITSET, ...)`", args)?;
+                let [_, _, _, timeout, uaddr2, bitset] = check_min_vararg_count(
+                    "`syscall(SYS_futex, FUTEX_WAIT_BITSET, ...)`",
+                    varargs,
+                )?;
                 let _timeout = ecx.read_pointer(timeout)?;
                 let _uaddr2 = ecx.read_pointer(uaddr2)?;
                 (timeout, ecx.read_scalar(bitset)?.to_u32()?)
             } else {
-                let [_, _, _, _, timeout] =
-                    check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT, ...)`", args)?;
+                let [_, _, _, timeout] =
+                    check_min_vararg_count("`syscall(SYS_futex, FUTEX_WAIT, ...)`", varargs)?;
                 (timeout, u32::MAX)
             };
 
@@ -156,14 +158,24 @@ pub fn futex<'tcx>(
                     .futex
                     .clone();
 
+                let dest = dest.clone();
                 ecx.futex_wait(
                     futex_ref,
                     bitset,
                     timeout,
-                    Scalar::from_target_isize(0, ecx), // retval_succ
-                    Scalar::from_target_isize(-1, ecx), // retval_timeout
-                    dest.clone(),
-                    LibcError("ETIMEDOUT"), // errno_timeout
+                    callback!(
+                        @capture<'tcx> {
+                            dest: MPlaceTy<'tcx>,
+                        }
+                        |ecx, unblock: UnblockKind| match unblock {
+                            UnblockKind::Ready => {
+                                ecx.write_int(0, &dest)
+                            }
+                            UnblockKind::TimedOut => {
+                                ecx.set_last_error_and_return(LibcError("ETIMEDOUT"), &dest)
+                            }
+                        }
+                    ),
                 );
             } else {
                 // The futex value doesn't match the expected value, so we return failure
@@ -190,8 +202,10 @@ pub fn futex<'tcx>(
             let futex_ref = futex_ref.futex.clone();
 
             let bitset = if op == futex_wake_bitset {
-                let [_, _, _, _, timeout, uaddr2, bitset] =
-                    check_min_arg_count("`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`", args)?;
+                let [_, _, _, timeout, uaddr2, bitset] = check_min_vararg_count(
+                    "`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`",
+                    varargs,
+                )?;
                 let _timeout = ecx.read_pointer(timeout)?;
                 let _uaddr2 = ecx.read_pointer(uaddr2)?;
                 ecx.read_scalar(bitset)?.to_u32()?
@@ -205,16 +219,8 @@ pub fn futex<'tcx>(
             // will see the latest value on addr which could be changed by our caller
             // before doing the syscall.
             ecx.atomic_fence(AtomicFenceOrd::SeqCst)?;
-            let mut n = 0;
-            #[expect(clippy::arithmetic_side_effects)]
-            for _ in 0..val {
-                if ecx.futex_wake(&futex_ref, bitset)? {
-                    n += 1;
-                } else {
-                    break;
-                }
-            }
-            ecx.write_scalar(Scalar::from_target_isize(n, ecx), dest)?;
+            let woken = ecx.futex_wake(&futex_ref, bitset, val.try_into().unwrap())?;
+            ecx.write_scalar(Scalar::from_target_isize(woken.try_into().unwrap(), ecx), dest)?;
         }
         op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op),
     }
diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
index 5fb262e176f..22c6dc97507 100644
--- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
@@ -2,7 +2,7 @@ use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
 use rustc_target::callconv::{Conv, FnAbi};
 
-use crate::helpers::check_min_arg_count;
+use crate::helpers::check_min_vararg_count;
 use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
 use crate::shims::unix::linux_like::sync::futex;
 use crate::*;
@@ -14,9 +14,7 @@ pub fn syscall<'tcx>(
     args: &[OpTy<'tcx>],
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx> {
-    // We do not use `check_shim` here because `syscall` is variadic. The argument
-    // count is checked bellow.
-    ecx.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
+    let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?;
     // The syscall variadic function is legal to call with more arguments than needed,
     // extra arguments are simply ignored. The important check is that when we use an
     // argument, we have to also check all arguments *before* it to ensure that they
@@ -26,14 +24,13 @@ pub fn syscall<'tcx>(
     let sys_futex = ecx.eval_libc("SYS_futex").to_target_usize(ecx)?;
     let sys_eventfd2 = ecx.eval_libc("SYS_eventfd2").to_target_usize(ecx)?;
 
-    let [op] = check_min_arg_count("syscall", args)?;
     match ecx.read_target_usize(op)? {
         // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
         // is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
         num if num == sys_getrandom => {
             // Used by getrandom 0.1
             // The first argument is the syscall id, so skip over it.
-            let [_, ptr, len, flags] = check_min_arg_count("syscall(SYS_getrandom, ...)", args)?;
+            let [ptr, len, flags] = check_min_vararg_count("syscall(SYS_getrandom, ...)", varargs)?;
 
             let ptr = ecx.read_pointer(ptr)?;
             let len = ecx.read_target_usize(len)?;
@@ -47,10 +44,10 @@ pub fn syscall<'tcx>(
         }
         // `futex` is used by some synchronization primitives.
         num if num == sys_futex => {
-            futex(ecx, args, dest)?;
+            futex(ecx, varargs, dest)?;
         }
         num if num == sys_eventfd2 => {
-            let [_, initval, flags] = check_min_arg_count("syscall(SYS_evetfd2, ...)", args)?;
+            let [initval, flags] = check_min_vararg_count("syscall(SYS_evetfd2, ...)", varargs)?;
 
             let result = ecx.eventfd(initval, flags)?;
             ecx.write_int(result.to_i32()?, dest)?;
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 85c963774a1..918fd8dd52d 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -2,13 +2,20 @@ use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
 use rustc_target::callconv::{Conv, FnAbi};
 
-use super::sync::EvalContextExt as _;
-use crate::helpers::check_min_arg_count;
+use super::sync::{EvalContextExt as _, MacOsFutexTimeout};
 use crate::shims::unix::*;
 use crate::*;
 
-pub fn is_dyn_sym(_name: &str) -> bool {
-    false
+pub fn is_dyn_sym(name: &str) -> bool {
+    match name {
+        // These only became available with macOS 11.0, so std looks them up dynamically.
+        "os_sync_wait_on_address"
+        | "os_sync_wait_on_address_with_deadline"
+        | "os_sync_wait_on_address_with_timeout"
+        | "os_sync_wake_by_address_any"
+        | "os_sync_wake_by_address_all" => true,
+        _ => false,
+    }
 }
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -40,17 +47,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "stat" | "stat64" | "stat$INODE64" => {
                 let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.macos_fbsd_solaris_stat(path, buf)?;
+                let result = this.macos_fbsd_solarish_stat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "lstat" | "lstat64" | "lstat$INODE64" => {
                 let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.macos_fbsd_solaris_lstat(path, buf)?;
+                let result = this.macos_fbsd_solarish_lstat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "fstat" | "fstat64" | "fstat$INODE64" => {
                 let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.macos_fbsd_solaris_fstat(fd, buf)?;
+                let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "opendir$INODE64" => {
@@ -69,10 +76,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
             "ioctl" => {
-                // `ioctl` is variadic. The argument count is checked based on the first argument
-                // in `this.ioctl()`, so we do not use `check_shim` here.
-                this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
-                let result = this.ioctl(args)?;
+                let ([fd_num, cmd], varargs) =
+                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                let result = this.ioctl(fd_num, cmd, varargs)?;
                 this.write_scalar(result, dest)?;
             }
 
@@ -216,6 +222,58 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
 
+            // Futex primitives
+            "os_sync_wait_on_address" => {
+                let [addr_op, value_op, size_op, flags_op] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                this.os_sync_wait_on_address(
+                    addr_op,
+                    value_op,
+                    size_op,
+                    flags_op,
+                    MacOsFutexTimeout::None,
+                    dest,
+                )?;
+            }
+            "os_sync_wait_on_address_with_deadline" => {
+                let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                this.os_sync_wait_on_address(
+                    addr_op,
+                    value_op,
+                    size_op,
+                    flags_op,
+                    MacOsFutexTimeout::Absolute { clock_op, timeout_op },
+                    dest,
+                )?;
+            }
+            "os_sync_wait_on_address_with_timeout" => {
+                let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                this.os_sync_wait_on_address(
+                    addr_op,
+                    value_op,
+                    size_op,
+                    flags_op,
+                    MacOsFutexTimeout::Relative { clock_op, timeout_op },
+                    dest,
+                )?;
+            }
+            "os_sync_wake_by_address_any" => {
+                let [addr_op, size_op, flags_op] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                this.os_sync_wake_by_address(
+                    addr_op, size_op, flags_op, /* all */ false, dest,
+                )?;
+            }
+            "os_sync_wake_by_address_all" => {
+                let [addr_op, size_op, flags_op] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                this.os_sync_wake_by_address(
+                    addr_op, size_op, flags_op, /* all */ true, dest,
+                )?;
+            }
+
             "os_unfair_lock_lock" => {
                 let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.os_unfair_lock_lock(lock_op)?;
@@ -243,12 +301,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(EmulateItemResult::NeedsReturn)
     }
 
-    fn ioctl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
+    fn ioctl(
+        &mut self,
+        fd_num: &OpTy<'tcx>,
+        cmd: &OpTy<'tcx>,
+        _varargs: &[OpTy<'tcx>],
+    ) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
         let fioclex = this.eval_libc_u64("FIOCLEX");
 
-        let [fd_num, cmd] = check_min_arg_count("ioctl", args)?;
         let fd_num = this.read_scalar(fd_num)?.to_i32()?;
         let cmd = this.read_scalar(cmd)?.to_u64()?;
 
diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs
index 330c64f06a3..6ba52f2f57e 100644
--- a/src/tools/miri/src/shims/unix/macos/sync.rs
+++ b/src/tools/miri/src/shims/unix/macos/sync.rs
@@ -10,8 +10,12 @@
 //! and we do not detect copying of the lock, but macOS doesn't guarantee anything
 //! in that case either.
 
+use std::cell::Cell;
+use std::time::Duration;
+
 use rustc_abi::Size;
 
+use crate::concurrency::sync::FutexRef;
 use crate::*;
 
 #[derive(Clone)]
@@ -20,6 +24,26 @@ enum MacOsUnfairLock {
     Active { mutex_ref: MutexRef },
 }
 
+pub enum MacOsFutexTimeout<'a, 'tcx> {
+    None,
+    Relative { clock_op: &'a OpTy<'tcx>, timeout_op: &'a OpTy<'tcx> },
+    Absolute { clock_op: &'a OpTy<'tcx>, timeout_op: &'a OpTy<'tcx> },
+}
+
+/// Metadata for a macOS futex.
+///
+/// Since macOS 11.0, Apple has exposed the previously private futex API consisting
+/// of `os_sync_wait_on_address` (and friends) and `os_sync_wake_by_address_{any, all}`.
+/// These work with different value sizes and flags, which are validated to be consistent.
+/// This structure keeps track of both the futex queue and these values.
+struct MacOsFutex {
+    futex: FutexRef,
+    /// The size in bytes of the atomic primitive underlying this futex.
+    size: Cell<u64>,
+    /// Whether the futex is shared across process boundaries.
+    shared: Cell<bool>,
+}
+
 impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn os_unfair_lock_get_data<'a>(
@@ -30,7 +54,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         'tcx: 'a,
     {
         let this = self.eval_context_mut();
-        let lock = this.deref_pointer(lock_ptr)?;
+        let lock = this.deref_pointer_as(lock_ptr, this.libc_ty_layout("os_unfair_lock_s"))?;
         this.lazy_sync_get_data(
             &lock,
             Size::ZERO, // offset for init tracking
@@ -54,6 +78,198 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    /// Implements [`os_sync_wait_on_address`], [`os_sync_wait_on_address_with_deadline`]
+    /// and [`os_sync_wait_on_address_with_timeout`].
+    ///
+    /// [`os_sync_wait_on_address`]: https://developer.apple.com/documentation/os/os_sync_wait_on_address?language=objc
+    /// [`os_sync_wait_on_address_with_deadline`]: https://developer.apple.com/documentation/os/os_sync_wait_on_address_with_deadline?language=objc
+    /// [`os_sync_wait_on_address_with_timeout`]: https://developer.apple.com/documentation/os/os_sync_wait_on_address_with_timeout?language=objc
+    fn os_sync_wait_on_address(
+        &mut self,
+        addr_op: &OpTy<'tcx>,
+        value_op: &OpTy<'tcx>,
+        size_op: &OpTy<'tcx>,
+        flags_op: &OpTy<'tcx>,
+        timeout: MacOsFutexTimeout<'_, 'tcx>,
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let none = this.eval_libc_u32("OS_SYNC_WAIT_ON_ADDRESS_NONE");
+        let shared = this.eval_libc_u32("OS_SYNC_WAIT_ON_ADDRESS_SHARED");
+        let absolute_clock = this.eval_libc_u32("OS_CLOCK_MACH_ABSOLUTE_TIME");
+
+        let ptr = this.read_pointer(addr_op)?;
+        let value = this.read_scalar(value_op)?.to_u64()?;
+        let size = this.read_target_usize(size_op)?;
+        let flags = this.read_scalar(flags_op)?.to_u32()?;
+
+        let clock_timeout = match timeout {
+            MacOsFutexTimeout::None => None,
+            MacOsFutexTimeout::Relative { clock_op, timeout_op } => {
+                let clock = this.read_scalar(clock_op)?.to_u32()?;
+                let timeout = this.read_scalar(timeout_op)?.to_u64()?;
+                Some((clock, TimeoutAnchor::Relative, timeout))
+            }
+            MacOsFutexTimeout::Absolute { clock_op, timeout_op } => {
+                let clock = this.read_scalar(clock_op)?.to_u32()?;
+                let timeout = this.read_scalar(timeout_op)?.to_u64()?;
+                Some((clock, TimeoutAnchor::Absolute, timeout))
+            }
+        };
+
+        // Perform validation of the arguments.
+        let addr = ptr.addr().bytes();
+        if addr == 0
+            || !matches!(size, 4 | 8)
+            || !addr.is_multiple_of(size)
+            || (flags != none && flags != shared)
+            || clock_timeout
+                .is_some_and(|(clock, _, timeout)| clock != absolute_clock || timeout == 0)
+        {
+            this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
+            return interp_ok(());
+        }
+
+        let is_shared = flags == shared;
+        let timeout = clock_timeout.map(|(_, anchor, timeout)| {
+            // The only clock that is currenlty supported is the monotonic clock.
+            // While the deadline argument of `os_sync_wait_on_address_with_deadline`
+            // is actually not in nanoseconds but in the units of `mach_current_time`,
+            // the two are equivalent in miri.
+            (TimeoutClock::Monotonic, anchor, Duration::from_nanos(timeout))
+        });
+
+        // See the Linux futex implementation for why this fence exists.
+        this.atomic_fence(AtomicFenceOrd::SeqCst)?;
+
+        let layout = this.machine.layouts.uint(Size::from_bytes(size)).unwrap();
+        let futex_val = this
+            .read_scalar_atomic(&this.ptr_to_mplace(ptr, layout), AtomicReadOrd::Acquire)?
+            .to_bits(Size::from_bytes(size))?;
+
+        let futex = this
+            .get_sync_or_init(ptr, |_| {
+                MacOsFutex {
+                    futex: Default::default(),
+                    size: Cell::new(size),
+                    shared: Cell::new(is_shared),
+                }
+            })
+            .unwrap();
+
+        // Detect mismatches between the flags and sizes used on this address
+        // by comparing it with the parameters used by the other waiters in
+        // the current list. If the list is currently empty, update those
+        // parameters.
+        if futex.futex.waiters() == 0 {
+            futex.size.set(size);
+            futex.shared.set(is_shared);
+        } else if futex.size.get() != size || futex.shared.get() != is_shared {
+            this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
+            return interp_ok(());
+        }
+
+        if futex_val == value.into() {
+            // If the values are the same, we have to block.
+            let futex_ref = futex.futex.clone();
+            let dest = dest.clone();
+            this.futex_wait(
+                futex_ref.clone(),
+                u32::MAX, // bitset
+                timeout,
+                callback!(
+                    @capture<'tcx> {
+                        dest: MPlaceTy<'tcx>,
+                        futex_ref: FutexRef,
+                    }
+                    |this, unblock: UnblockKind| {
+                        match unblock {
+                            UnblockKind::Ready => {
+                                let remaining = futex_ref.waiters().try_into().unwrap();
+                                this.write_scalar(Scalar::from_i32(remaining), &dest)
+                            }
+                            UnblockKind::TimedOut => {
+                                this.set_last_error_and_return(LibcError("ETIMEDOUT"), &dest)
+                            }
+                        }
+                    }
+                ),
+            );
+        } else {
+            // else retrieve the current number of waiters.
+            let waiters = futex.futex.waiters().try_into().unwrap();
+            this.write_scalar(Scalar::from_i32(waiters), dest)?;
+        }
+
+        interp_ok(())
+    }
+
+    /// Implements [`os_sync_wake_by_address_all`] and [`os_sync_wake_by_address_any`].
+    ///
+    /// [`os_sync_wake_by_address_all`]: https://developer.apple.com/documentation/os/os_sync_wake_by_address_all?language=objc
+    /// [`os_sync_wake_by_address_any`]: https://developer.apple.com/documentation/os/os_sync_wake_by_address_any?language=objc
+    fn os_sync_wake_by_address(
+        &mut self,
+        addr_op: &OpTy<'tcx>,
+        size_op: &OpTy<'tcx>,
+        flags_op: &OpTy<'tcx>,
+        all: bool,
+        dest: &MPlaceTy<'tcx>,
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let none = this.eval_libc_u32("OS_SYNC_WAKE_BY_ADDRESS_NONE");
+        let shared = this.eval_libc_u32("OS_SYNC_WAKE_BY_ADDRESS_SHARED");
+
+        let ptr = this.read_pointer(addr_op)?;
+        let size = this.read_target_usize(size_op)?;
+        let flags = this.read_scalar(flags_op)?.to_u32()?;
+
+        // Perform validation of the arguments.
+        let addr = ptr.addr().bytes();
+        if addr == 0 || !matches!(size, 4 | 8) || (flags != none && flags != shared) {
+            this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
+            return interp_ok(());
+        }
+
+        let is_shared = flags == shared;
+
+        let Some(futex) = this.get_sync_or_init(ptr, |_| {
+            MacOsFutex {
+                futex: Default::default(),
+                size: Cell::new(size),
+                shared: Cell::new(is_shared),
+            }
+        }) else {
+            // No AllocId, or no live allocation at that AllocId. Return an
+            // error code. (That seems nicer than silently doing something
+            // non-intuitive.) This means that if an address gets reused by a
+            // new allocation, we'll use an independent futex queue for this...
+            // that seems acceptable.
+            this.set_last_error_and_return(LibcError("ENOENT"), dest)?;
+            return interp_ok(());
+        };
+
+        if futex.futex.waiters() == 0 {
+            this.set_last_error_and_return(LibcError("ENOENT"), dest)?;
+            return interp_ok(());
+        // If there are waiters in the queue, they have all used the parameters
+        // stored in `futex` (we check this in `os_sync_wait_on_address` above).
+        // Detect mismatches between "our" parameters and the parameters used by
+        // the waiters and return an error in that case.
+        } else if futex.size.get() != size || futex.shared.get() != is_shared {
+            this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
+            return interp_ok(());
+        }
+
+        let futex_ref = futex.futex.clone();
+
+        // See the Linux futex implementation for why this fence exists.
+        this.atomic_fence(AtomicFenceOrd::SeqCst)?;
+        this.futex_wake(&futex_ref, u32::MAX, if all { usize::MAX } else { 1 })?;
+        this.write_scalar(Scalar::from_i32(0), dest)?;
+        interp_ok(())
+    }
+
     fn os_unfair_lock_lock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index 5531b944e17..aefeee6f7a3 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -111,15 +111,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
-        let ptr =
-            this.allocate_ptr(Size::from_bytes(map_length), align, MiriMemoryKind::Mmap.into())?;
-        // We just allocated this, the access is definitely in-bounds and fits into our address space.
-        // mmap guarantees new mappings are zero-init.
-        this.write_bytes_ptr(
-            ptr.into(),
-            std::iter::repeat(0u8).take(usize::try_from(map_length).unwrap()),
-        )
-        .unwrap();
+        let ptr = this.allocate_ptr(
+            Size::from_bytes(map_length),
+            align,
+            MiriMemoryKind::Mmap.into(),
+            // mmap guarantees new mappings are zero-init.
+            AllocInit::Zero,
+        )?;
 
         interp_ok(Scalar::from_pointer(ptr, this))
     }
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index f94783a3907..21d4f41f485 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -87,17 +87,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // File related shims
             "stat" | "stat64" => {
                 let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.macos_fbsd_solaris_stat(path, buf)?;
+                let result = this.macos_fbsd_solarish_stat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "lstat" | "lstat64" => {
                 let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.macos_fbsd_solaris_lstat(path, buf)?;
+                let result = this.macos_fbsd_solarish_lstat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "fstat" | "fstat64" => {
                 let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let result = this.macos_fbsd_solaris_fstat(fd, buf)?;
+                let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "readdir" => {
@@ -163,7 +163,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     throw_unsup_format!("pset_info is only supported with list==NULL");
                 }
 
-                let cpus = this.deref_pointer(cpus)?;
+                let cpus = this.deref_pointer_as(cpus, this.machine.layouts.u32)?;
                 this.write_scalar(Scalar::from_u32(this.machine.num_cpus), &cpus)?;
                 this.write_null(dest)?;
             }
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index 5b0a9398b4b..9f1fabfbf64 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -170,7 +170,7 @@ fn mutex_create<'tcx>(
     mutex_ptr: &OpTy<'tcx>,
     kind: MutexKind,
 ) -> InterpResult<'tcx, PthreadMutex> {
-    let mutex = ecx.deref_pointer(mutex_ptr)?;
+    let mutex = ecx.deref_pointer_as(mutex_ptr, ecx.libc_ty_layout("pthread_mutex_t"))?;
     let id = ecx.machine.sync.mutex_create();
     let data = PthreadMutex { mutex_ref: id, kind };
     ecx.lazy_sync_init(&mutex, mutex_init_offset(ecx)?, data.clone())?;
@@ -186,7 +186,7 @@ fn mutex_get_data<'tcx, 'a>(
 where
     'tcx: 'a,
 {
-    let mutex = ecx.deref_pointer(mutex_ptr)?;
+    let mutex = ecx.deref_pointer_as(mutex_ptr, ecx.libc_ty_layout("pthread_mutex_t"))?;
     ecx.lazy_sync_get_data(
         &mutex,
         mutex_init_offset(ecx)?,
@@ -265,7 +265,7 @@ fn rwlock_get_data<'tcx, 'a>(
 where
     'tcx: 'a,
 {
-    let rwlock = ecx.deref_pointer(rwlock_ptr)?;
+    let rwlock = ecx.deref_pointer_as(rwlock_ptr, ecx.libc_ty_layout("pthread_rwlock_t"))?;
     ecx.lazy_sync_get_data(
         &rwlock,
         rwlock_init_offset(ecx)?,
@@ -383,7 +383,7 @@ fn cond_create<'tcx>(
     cond_ptr: &OpTy<'tcx>,
     clock: ClockId,
 ) -> InterpResult<'tcx, PthreadCondvar> {
-    let cond = ecx.deref_pointer(cond_ptr)?;
+    let cond = ecx.deref_pointer_as(cond_ptr, ecx.libc_ty_layout("pthread_cond_t"))?;
     let id = ecx.machine.sync.condvar_create();
     let data = PthreadCondvar { id, clock };
     ecx.lazy_sync_init(&cond, cond_init_offset(ecx)?, data)?;
@@ -397,7 +397,7 @@ fn cond_get_data<'tcx, 'a>(
 where
     'tcx: 'a,
 {
-    let cond = ecx.deref_pointer(cond_ptr)?;
+    let cond = ecx.deref_pointer_as(cond_ptr, ecx.libc_ty_layout("pthread_cond_t"))?;
     ecx.lazy_sync_get_data(
         &cond,
         cond_init_offset(ecx)?,
@@ -760,7 +760,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let clock_id = condattr_get_clock_id(this, attr_op)?;
-        this.write_scalar(Scalar::from_i32(clock_id), &this.deref_pointer(clk_id_op)?)?;
+        this.write_scalar(
+            Scalar::from_i32(clock_id),
+            &this.deref_pointer_as(clk_id_op, this.libc_ty_layout("clockid_t"))?,
+        )?;
 
         interp_ok(())
     }
diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs
index 08515b815a9..e183bfdf0e1 100644
--- a/src/tools/miri/src/shims/unix/unnamed_socket.rs
+++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs
@@ -5,9 +5,7 @@
 use std::cell::{Cell, OnceCell, RefCell};
 use std::collections::VecDeque;
 use std::io;
-use std::io::{ErrorKind, Read};
-
-use rustc_abi::Size;
+use std::io::ErrorKind;
 
 use crate::concurrency::VClock;
 use crate::shims::files::{
@@ -92,10 +90,10 @@ impl FileDescription for AnonSocket {
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
-        anonsocket_read(self, len, ptr, dest, ecx)
+        anonsocket_read(self, ptr, len, ecx, finish)
     }
 
     fn write<'tcx>(
@@ -103,10 +101,10 @@ impl FileDescription for AnonSocket {
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
-        dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
+        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
     ) -> InterpResult<'tcx> {
-        anonsocket_write(self, ptr, len, dest, ecx)
+        anonsocket_write(self, ptr, len, ecx, finish)
     }
 
     fn as_unix(&self) -> &dyn UnixFileDescription {
@@ -119,25 +117,25 @@ fn anonsocket_write<'tcx>(
     self_ref: FileDescriptionRef<AnonSocket>,
     ptr: Pointer,
     len: usize,
-    dest: &MPlaceTy<'tcx>,
     ecx: &mut MiriInterpCx<'tcx>,
+    finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
 ) -> InterpResult<'tcx> {
     // Always succeed on write size 0.
     // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.")
     if len == 0 {
-        return ecx.return_write_success(0, dest);
+        return finish.call(ecx, Ok(0));
     }
 
     // We are writing to our peer's readbuf.
     let Some(peer_fd) = self_ref.peer_fd().upgrade() else {
         // If the upgrade from Weak to Rc fails, it indicates that all read ends have been
         // closed. It is an error to write even if there would be space.
-        return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest);
+        return finish.call(ecx, Err(ErrorKind::BrokenPipe.into()));
     };
 
     let Some(writebuf) = &peer_fd.readbuf else {
         // Writing to the read end of a pipe.
-        return ecx.set_last_error_and_return(IoError::LibcError("EBADF"), dest);
+        return finish.call(ecx, Err(IoError::LibcError("EBADF")));
     };
 
     // Let's see if we can write.
@@ -145,13 +143,12 @@ fn anonsocket_write<'tcx>(
     if available_space == 0 {
         if self_ref.is_nonblock {
             // Non-blocking socketpair with a full buffer.
-            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
+            return finish.call(ecx, Err(ErrorKind::WouldBlock.into()));
         } else {
             self_ref.blocked_write_tid.borrow_mut().push(ecx.active_thread());
             // Blocking socketpair with a full buffer.
             // Block the current thread; only keep a weak ref for this.
             let weak_self_ref = FileDescriptionRef::downgrade(&self_ref);
-            let dest = dest.clone();
             ecx.block_thread(
                 BlockReason::UnnamedSocket,
                 None,
@@ -160,14 +157,14 @@ fn anonsocket_write<'tcx>(
                         weak_self_ref: WeakFileDescriptionRef<AnonSocket>,
                         ptr: Pointer,
                         len: usize,
-                        dest: MPlaceTy<'tcx>,
+                        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
                     }
                     |this, unblock: UnblockKind| {
                         assert_eq!(unblock, UnblockKind::Ready);
                         // If we got unblocked, then our peer successfully upgraded its weak
                         // ref to us. That means we can also upgrade our weak ref.
                         let self_ref = weak_self_ref.upgrade().unwrap();
-                        anonsocket_write(self_ref, ptr, len, &dest, this)
+                        anonsocket_write(self_ref, ptr, len, this, finish)
                     }
                 ),
             );
@@ -180,9 +177,9 @@ fn anonsocket_write<'tcx>(
             writebuf.clock.join(clock);
         });
         // Do full write / partial write based on the space available.
-        let actual_write_size = len.min(available_space);
-        let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
-        writebuf.buf.extend(&bytes[..actual_write_size]);
+        let write_size = len.min(available_space);
+        let actual_write_size = ecx.write_to_host(&mut writebuf.buf, write_size, ptr)?.unwrap();
+        assert_eq!(actual_write_size, write_size);
 
         // Need to stop accessing peer_fd so that it can be notified.
         drop(writebuf);
@@ -197,7 +194,7 @@ fn anonsocket_write<'tcx>(
         // The kernel does this even if the fd was already readable before, so we follow suit.
         ecx.check_and_update_readiness(peer_fd)?;
 
-        return ecx.return_write_success(actual_write_size, dest);
+        return finish.call(ecx, Ok(write_size));
     }
     interp_ok(())
 }
@@ -205,14 +202,14 @@ fn anonsocket_write<'tcx>(
 /// Read from AnonSocket and return the number of bytes read.
 fn anonsocket_read<'tcx>(
     self_ref: FileDescriptionRef<AnonSocket>,
-    len: usize,
     ptr: Pointer,
-    dest: &MPlaceTy<'tcx>,
+    len: usize,
     ecx: &mut MiriInterpCx<'tcx>,
+    finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
 ) -> InterpResult<'tcx> {
     // Always succeed on read size 0.
     if len == 0 {
-        return ecx.return_read_success(ptr, &[], 0, dest);
+        return finish.call(ecx, Ok(0));
     }
 
     let Some(readbuf) = &self_ref.readbuf else {
@@ -225,43 +222,41 @@ fn anonsocket_read<'tcx>(
         if self_ref.peer_fd().upgrade().is_none() {
             // Socketpair with no peer and empty buffer.
             // 0 bytes successfully read indicates end-of-file.
-            return ecx.return_read_success(ptr, &[], 0, dest);
+            return finish.call(ecx, Ok(0));
         } else if self_ref.is_nonblock {
             // Non-blocking socketpair with writer and empty buffer.
             // https://linux.die.net/man/2/read
             // EAGAIN or EWOULDBLOCK can be returned for socket,
             // POSIX.1-2001 allows either error to be returned for this case.
             // Since there is no ErrorKind for EAGAIN, WouldBlock is used.
-            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
+            return finish.call(ecx, Err(ErrorKind::WouldBlock.into()));
         } else {
             self_ref.blocked_read_tid.borrow_mut().push(ecx.active_thread());
             // Blocking socketpair with writer and empty buffer.
             // Block the current thread; only keep a weak ref for this.
             let weak_self_ref = FileDescriptionRef::downgrade(&self_ref);
-            let dest = dest.clone();
             ecx.block_thread(
                 BlockReason::UnnamedSocket,
                 None,
                 callback!(
                     @capture<'tcx> {
                         weak_self_ref: WeakFileDescriptionRef<AnonSocket>,
-                        len: usize,
                         ptr: Pointer,
-                        dest: MPlaceTy<'tcx>,
+                        len: usize,
+                        finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
                     }
                     |this, unblock: UnblockKind| {
                         assert_eq!(unblock, UnblockKind::Ready);
                         // If we got unblocked, then our peer successfully upgraded its weak
                         // ref to us. That means we can also upgrade our weak ref.
                         let self_ref = weak_self_ref.upgrade().unwrap();
-                        anonsocket_read(self_ref, len, ptr, &dest, this)
+                        anonsocket_read(self_ref, ptr, len, this, finish)
                     }
                 ),
             );
         }
     } else {
         // There's data to be read!
-        let mut bytes = vec![0; len];
         let mut readbuf = readbuf.borrow_mut();
         // Synchronize with all previous writes to this buffer.
         // FIXME: this over-synchronizes; a more precise approach would be to
@@ -270,7 +265,7 @@ fn anonsocket_read<'tcx>(
 
         // Do full read / partial read based on the space available.
         // Conveniently, `read` exists on `VecDeque` and has exactly the desired behavior.
-        let actual_read_size = readbuf.buf.read(&mut bytes[..]).unwrap();
+        let read_size = ecx.read_from_host(&mut readbuf.buf, len, ptr)?.unwrap();
 
         // Need to drop before others can access the readbuf again.
         drop(readbuf);
@@ -293,7 +288,7 @@ fn anonsocket_read<'tcx>(
             ecx.check_and_update_readiness(peer_fd)?;
         };
 
-        return ecx.return_read_success(ptr, &bytes, actual_read_size, dest);
+        return finish.call(ecx, Ok(read_size));
     }
     interp_ok(())
 }
@@ -362,7 +357,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let domain = this.read_scalar(domain)?.to_i32()?;
         let mut flags = this.read_scalar(type_)?.to_i32()?;
         let protocol = this.read_scalar(protocol)?.to_i32()?;
-        let sv = this.deref_pointer(sv)?;
+        // This is really a pointer to `[i32; 2]` but we use a ptr-to-first-element representation.
+        let sv = this.deref_pointer_as(sv, this.machine.layouts.i32)?;
 
         let mut is_sock_nonblock = false;
 
diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs
index 72c1fb58023..1b2ccd99ef9 100644
--- a/src/tools/miri/src/shims/windows/env.rs
+++ b/src/tools/miri/src/shims/windows/env.rs
@@ -218,7 +218,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let token = this.read_target_isize(token)?;
         let buf = this.read_pointer(buf)?;
-        let size = this.deref_pointer(size)?;
+        let size = this.deref_pointer_as(size, this.machine.layouts.u32)?;
 
         if token != -4 {
             throw_unsup_format!(
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 0bf56c3d005..fae6170a9e7 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -253,8 +253,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.read_target_isize(handle)?;
                 let flags = this.read_scalar(flags)?.to_u32()?;
                 let size = this.read_target_usize(size)?;
-                let heap_zero_memory = 0x00000008; // HEAP_ZERO_MEMORY
-                let zero_init = (flags & heap_zero_memory) == heap_zero_memory;
+                const HEAP_ZERO_MEMORY: u32 = 0x00000008;
+                let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
+                    AllocInit::Zero
+                } else {
+                    AllocInit::Uninit
+                };
                 // Alignment is twice the pointer size.
                 // Source: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc>
                 let align = this.tcx.pointer_size().bytes().strict_mul(2);
@@ -262,13 +266,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(size),
                     Align::from_bytes(align).unwrap(),
                     MiriMemoryKind::WinHeap.into(),
+                    init,
                 )?;
-                if zero_init {
-                    this.write_bytes_ptr(
-                        ptr.into(),
-                        iter::repeat(0u8).take(usize::try_from(size).unwrap()),
-                    )?;
-                }
                 this.write_pointer(ptr, dest)?;
             }
             "HeapFree" => {
@@ -300,6 +299,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(size),
                     Align::from_bytes(align).unwrap(),
                     MiriMemoryKind::WinHeap.into(),
+                    AllocInit::Uninit,
                 )?;
                 this.write_pointer(new_ptr, dest)?;
             }
@@ -335,7 +335,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Initialize with `0`.
                 this.write_bytes_ptr(
                     system_info.ptr(),
-                    iter::repeat(0u8).take(system_info.layout.size.bytes_usize()),
+                    iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
                 )?;
                 // Set selected fields.
                 this.write_int_fields_named(
@@ -523,7 +523,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
 
                 let handle = this.read_scalar(handle)?;
-                let name_ptr = this.deref_pointer(name_ptr)?; // the pointer where we should store the ptr to the name
+                let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; // the pointer where we should store the ptr to the name
 
                 let thread = match Handle::try_from_scalar(handle, this)? {
                     Ok(Handle::Thread(thread)) => Ok(thread),
@@ -725,7 +725,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "GetConsoleMode" if this.frame_in_std() => {
                 let [console, mode] = this.check_shim(abi, sys_conv, link_name, args)?;
                 this.read_target_isize(console)?;
-                this.deref_pointer(mode)?;
+                this.deref_pointer_as(mode, this.machine.layouts.u32)?;
                 // Indicate an error.
                 this.write_null(dest)?;
             }
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index 4001201bf67..8d5ea7db9e4 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -29,7 +29,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     {
         let this = self.eval_context_mut();
 
-        let init_once = this.deref_pointer(init_once_ptr)?;
+        let init_once =
+            this.deref_pointer_as(init_once_ptr, this.windows_ty_layout("INIT_ONCE"))?;
         let init_offset = Size::ZERO;
 
         this.lazy_sync_get_data(
@@ -85,7 +86,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let id = this.init_once_get_data(init_once_op)?.id;
         let flags = this.read_scalar(flags_op)?.to_u32()?;
-        let pending_place = this.deref_pointer(pending_op)?;
+        // PBOOL is int*
+        let pending_place = this.deref_pointer_as(pending_op, this.machine.layouts.i32)?;
         let context = this.read_pointer(context_op)?;
 
         if flags != 0 {
@@ -210,14 +212,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 .futex
                 .clone();
 
+            let dest = dest.clone();
             this.futex_wait(
                 futex_ref,
                 u32::MAX, // bitset
                 timeout,
-                Scalar::from_i32(1), // retval_succ
-                Scalar::from_i32(0), // retval_timeout
-                dest.clone(),
-                IoError::WindowsError("ERROR_TIMEOUT"), // errno_timeout
+                callback!(
+                    @capture<'tcx> {
+                        dest: MPlaceTy<'tcx>
+                    }
+                    |this, unblock: UnblockKind| {
+                        match unblock {
+                            UnblockKind::Ready => {
+                                this.write_int(1, &dest)
+                            }
+                            UnblockKind::TimedOut => {
+                                this.set_last_error(IoError::WindowsError("ERROR_TIMEOUT"))?;
+                                this.write_int(0, &dest)
+                            }
+                        }
+                    }
+                ),
             );
         }
 
@@ -242,7 +257,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
         let futex_ref = futex_ref.futex.clone();
 
-        this.futex_wake(&futex_ref, u32::MAX)?;
+        this.futex_wake(&futex_ref, u32::MAX, 1)?;
 
         interp_ok(())
     }
@@ -262,7 +277,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
         let futex_ref = futex_ref.futex.clone();
 
-        while this.futex_wake(&futex_ref, u32::MAX)? {}
+        this.futex_wake(&futex_ref, u32::MAX, usize::MAX)?;
 
         interp_ok(())
     }
diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs
index efc1c2286bc..5db55404422 100644
--- a/src/tools/miri/src/shims/windows/thread.rs
+++ b/src/tools/miri/src/shims/windows/thread.rs
@@ -29,7 +29,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let thread = if this.ptr_is_null(this.read_pointer(thread_op)?)? {
             None
         } else {
-            let thread_info_place = this.deref_pointer(thread_op)?;
+            let thread_info_place = this.deref_pointer_as(thread_op, this.machine.layouts.u32)?;
             Some(thread_info_place)
         };
 
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index 0a5e9f62dd9..af92f9d0dec 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -106,6 +106,18 @@ dependencies = [
 ]
 
 [[package]]
+name = "getrandom"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.13.3+wasi-0.2.2",
+ "windows-targets",
+]
+
+[[package]]
 name = "gimli"
 version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -178,6 +190,7 @@ dependencies = [
  "cfg-if",
  "getrandom 0.1.16",
  "getrandom 0.2.15",
+ "getrandom 0.3.1",
  "libc",
  "num_cpus",
  "page_size",
@@ -360,6 +373,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
+name = "wasi"
+version = "0.13.3+wasi-0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
 name = "wasm-bindgen"
 version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -507,3 +529,12 @@ name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+dependencies = [
+ "bitflags",
+]
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index e7eff46afca..78dddaf11df 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -8,13 +8,14 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
-# all dependencies (and their transitive ones) listed here can be used in `tests/`.
+# all dependencies (and their transitive ones) listed here can be used in `tests/*-dep`.
 libc = "0.2"
 num_cpus = "1.10.1"
 cfg-if = "1"
 
 getrandom_01 = { package = "getrandom", version = "0.1" }
 getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] }
+getrandom_03 = { package = "getrandom", version = "0.3" }
 
 [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
 tempfile = "3"
diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs
index 4b6f344a78e..457f32e5544 100644
--- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs
+++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs
@@ -8,5 +8,5 @@ fn main() {
 fn test_file_open_missing_needed_mode() {
     let name = b"missing_arg.txt\0";
     let name_ptr = name.as_ptr().cast::<libc::c_char>();
-    let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: incorrect number of arguments for `open(pathname, O_CREAT, ...)`: got 2, expected at least 3
+    let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: not enough variadic arguments
 }
diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr
index ca9e3c6c4be..f48b75460d4 100644
--- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: incorrect number of arguments for `open(pathname, O_CREAT, ...)`: got 2, expected at least 3
+error: Undefined Behavior: not enough variadic arguments for `open(pathname, O_CREAT, ...)`: got 0, expected at least 1
   --> tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC
    |
-LL | ... { libc::open(name_ptr, libc::O_CREAT) };
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of arguments for `open(pathname, O_CREAT, ...)`: got 2, expected at least 3
+LL |     let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) };
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not enough variadic arguments for `open(pathname, O_CREAT, ...)`: got 0, expected at least 1
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs
new file mode 100644
index 00000000000..5a997ad8ec4
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs
@@ -0,0 +1,5 @@
+fn main() {
+    unsafe {
+        (&1_u8 as *const u8).offset_from(&2_u8); //~ERROR: not both derived from the same allocation
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr
new file mode 100644
index 00000000000..34d7c6a8021
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
+  --> tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC
+   |
+LL |         (&1_u8 as *const u8).offset_from(&2_u8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
index 0acda559d3a..0d34e711ca7 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
@@ -15,6 +15,6 @@ fn main() {
         let _ = p1.byte_offset_from(p1);
 
         // UB because different pointers.
-        let _ = p1.byte_offset_from(p2); //~ERROR: no provenance
+        let _ = p1.byte_offset_from(p2); //~ERROR: not both derived from the same allocation
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
index 7ef66390fcd..897945d6d5d 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
   --> tests/fail/intrinsics/ptr_offset_from_different_ints.rs:LL:CC
    |
 LL |         let _ = p1.byte_offset_from(p2);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance)
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs
new file mode 100644
index 00000000000..06f6b7a0117
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let mem = [0u8; 1];
+    let ptr = mem.as_ptr();
+    unsafe {
+        ptr.wrapping_add(4).offset_from(ptr); //~ERROR: the memory range between them is not in-bounds of an allocation
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr
new file mode 100644
index 00000000000..67df633bef5
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
+  --> tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC
+   |
+LL |         ptr.wrapping_add(4).offset_from(ptr);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs
index a20539ee7c7..c557c35c9de 100644
--- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs
+++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs
@@ -1,10 +1,13 @@
 extern "Rust" {
-    fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
+    fn miri_backtrace_size(flags: u64) -> usize;
+    fn miri_get_backtrace(flags: u64, buf: *mut *mut ());
     fn miri_resolve_frame(ptr: *mut (), flags: u64);
 }
 
 fn main() {
-    let frames = unsafe { miri_get_backtrace(0) };
+    let size = unsafe { miri_backtrace_size(0) };
+    let mut frames = vec![std::ptr::null_mut(); size];
+    unsafe { miri_get_backtrace(1, frames.as_mut_ptr()) };
     for frame in frames.iter() {
         unsafe {
             miri_resolve_frame(*frame, 0); //~ ERROR: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields
diff --git a/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.rs b/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.rs
new file mode 100644
index 00000000000..b920e6795f9
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.rs
@@ -0,0 +1,17 @@
+//@ignore-target: windows # File handling is not implemented yet
+//@compile-flags: -Zmiri-disable-isolation
+use std::ffi::{CString, OsStr, c_char, c_int};
+use std::os::unix::ffi::OsStrExt;
+
+// Declare a variadic function as non-variadic.
+extern "C" {
+    fn open(path: *const c_char, oflag: c_int) -> c_int;
+}
+
+fn main() {
+    let c_path = CString::new(OsStr::new("./text").as_bytes()).expect("CString::new failed");
+    let _fd = unsafe {
+        open(c_path.as_ptr(), /* value does not matter */ 0)
+        //~^ ERROR: calling a variadic function with a non-variadic caller-side signature
+    };
+}
diff --git a/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.stderr b/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.stderr
new file mode 100644
index 00000000000..43813af9a3c
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: calling a variadic function with a non-variadic caller-side signature
+  --> tests/fail/shims/non_vararg_signature_mismatch.rs:LL:CC
+   |
+LL |         open(c_path.as_ptr(), /* value does not matter */ 0)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a variadic function with a non-variadic caller-side signature
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/shims/non_vararg_signature_mismatch.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.rs b/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.rs
new file mode 100644
index 00000000000..e9cb69418d2
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.rs
@@ -0,0 +1,16 @@
+//@ignore-target: windows # File handling is not implemented yet
+//@compile-flags: -Zmiri-disable-isolation
+use std::ffi::{CString, OsStr, c_char, c_int};
+use std::os::unix::ffi::OsStrExt;
+
+extern "C" {
+    fn open(path: *const c_char, ...) -> c_int;
+}
+
+fn main() {
+    let c_path = CString::new(OsStr::new("./text").as_bytes()).expect("CString::new failed");
+    let _fd = unsafe {
+        open(c_path.as_ptr(), /* value does not matter */ 0)
+        //~^ ERROR: incorrect number of fixed arguments for variadic function
+    };
+}
diff --git a/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.stderr b/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.stderr
new file mode 100644
index 00000000000..12e464813cf
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: incorrect number of fixed arguments for variadic function `open`: got 1, expected 2
+  --> tests/fail/shims/wrong_fixed_arg_count.rs:LL:CC
+   |
+LL |         open(c_path.as_ptr(), /* value does not matter */ 0)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of fixed arguments for variadic function `open`: got 1, expected 2
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/shims/wrong_fixed_arg_count.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs
new file mode 100644
index 00000000000..becb90eb923
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs
@@ -0,0 +1,276 @@
+//@only-target: darwin
+//@compile-flags: -Zmiri-preemption-rate=0
+
+use std::time::{Duration, Instant};
+use std::{io, ptr, thread};
+
+fn wake_nobody() {
+    let futex = 0;
+
+    // Wake 1 waiter. Expect ENOENT as nobody is waiting.
+    unsafe {
+        assert_eq!(
+            libc::os_sync_wake_by_address_any(
+                ptr::from_ref(&futex).cast_mut().cast(),
+                size_of::<i32>(),
+                libc::OS_SYNC_WAKE_BY_ADDRESS_NONE
+            ),
+            -1
+        );
+        assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ENOENT);
+    }
+}
+
+fn wake_dangling() {
+    let futex = Box::new(0);
+    let ptr = ptr::from_ref(&futex).cast_mut().cast();
+    drop(futex);
+
+    // Expect error since this is now "unmapped" memory.
+    unsafe {
+        assert_eq!(
+            libc::os_sync_wake_by_address_any(
+                ptr,
+                size_of::<i32>(),
+                libc::OS_SYNC_WAKE_BY_ADDRESS_NONE
+            ),
+            -1
+        );
+        assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ENOENT);
+    }
+}
+
+fn wait_wrong_val() {
+    let futex: i32 = 123;
+
+    // Only wait if the futex value is 456.
+    unsafe {
+        assert_eq!(
+            libc::os_sync_wait_on_address(
+                ptr::from_ref(&futex).cast_mut().cast(),
+                456,
+                size_of::<i32>(),
+                libc::OS_SYNC_WAIT_ON_ADDRESS_NONE
+            ),
+            0,
+        );
+    }
+}
+
+fn wait_timeout() {
+    let start = Instant::now();
+
+    let futex: i32 = 123;
+
+    // Wait for 200ms, with nobody waking us up early.
+    unsafe {
+        assert_eq!(
+            libc::os_sync_wait_on_address_with_timeout(
+                ptr::from_ref(&futex).cast_mut().cast(),
+                123,
+                size_of::<i32>(),
+                libc::OS_SYNC_WAIT_ON_ADDRESS_NONE,
+                libc::OS_CLOCK_MACH_ABSOLUTE_TIME,
+                200_000_000,
+            ),
+            -1,
+        );
+        assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT);
+    }
+
+    assert!((200..1000).contains(&start.elapsed().as_millis()));
+}
+
+fn wait_absolute_timeout() {
+    let start = Instant::now();
+
+    // Get the current monotonic timestamp.
+    #[allow(deprecated)]
+    let mut deadline = unsafe { libc::mach_absolute_time() };
+
+    // Add 200ms.
+    // What we should be doing here is call `mach_timebase_info` to determine the
+    // unit used for `deadline`, but we know what Miri returns for that function:
+    // the unit is nanoseconds.
+    deadline += 200_000_000;
+
+    let futex: i32 = 123;
+
+    // Wait for 200ms from now, with nobody waking us up early.
+    unsafe {
+        assert_eq!(
+            libc::os_sync_wait_on_address_with_deadline(
+                ptr::from_ref(&futex).cast_mut().cast(),
+                123,
+                size_of::<i32>(),
+                libc::OS_SYNC_WAIT_ON_ADDRESS_NONE,
+                libc::OS_CLOCK_MACH_ABSOLUTE_TIME,
+                deadline,
+            ),
+            -1,
+        );
+        assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT);
+    }
+
+    assert!((200..1000).contains(&start.elapsed().as_millis()));
+}
+
+fn wait_wake() {
+    let start = Instant::now();
+
+    static mut FUTEX: i32 = 0;
+
+    let t = thread::spawn(move || {
+        thread::sleep(Duration::from_millis(200));
+        unsafe {
+            assert_eq!(
+                libc::os_sync_wake_by_address_any(
+                    (&raw const FUTEX).cast_mut().cast(),
+                    size_of::<i32>(),
+                    libc::OS_SYNC_WAKE_BY_ADDRESS_NONE,
+                ),
+                0,
+            );
+        }
+    });
+
+    unsafe {
+        assert_eq!(
+            libc::os_sync_wait_on_address(
+                (&raw const FUTEX).cast_mut().cast(),
+                0,
+                size_of::<i32>(),
+                libc::OS_SYNC_WAIT_ON_ADDRESS_NONE,
+            ),
+            0,
+        );
+    }
+
+    // When running this in stress-gc mode, things can take quite long.
+    // So the timeout is 3000 ms.
+    assert!((200..3000).contains(&start.elapsed().as_millis()));
+    t.join().unwrap();
+}
+
+fn wait_wake_multiple() {
+    let val = 0i32;
+    let futex = &val;
+
+    thread::scope(|s| {
+        // Spawn some threads and make them wait on the futex.
+        for i in 0..4 {
+            s.spawn(move || unsafe {
+                assert_eq!(
+                    libc::os_sync_wait_on_address(
+                        ptr::from_ref(futex).cast_mut().cast(),
+                        0,
+                        size_of::<i32>(),
+                        libc::OS_SYNC_WAIT_ON_ADDRESS_NONE,
+                    ),
+                    // The last two threads will be woken at the same time,
+                    // but for the first two threads the remaining number
+                    // of waiters should be strictly decreasing.
+                    if i < 2 { 3 - i } else { 0 },
+                );
+            });
+
+            thread::yield_now();
+        }
+
+        // Wake the threads up again.
+        unsafe {
+            assert_eq!(
+                libc::os_sync_wake_by_address_any(
+                    ptr::from_ref(futex).cast_mut().cast(),
+                    size_of::<i32>(),
+                    libc::OS_SYNC_WAKE_BY_ADDRESS_NONE,
+                ),
+                0
+            );
+
+            assert_eq!(
+                libc::os_sync_wake_by_address_any(
+                    ptr::from_ref(futex).cast_mut().cast(),
+                    size_of::<i32>(),
+                    libc::OS_SYNC_WAKE_BY_ADDRESS_NONE,
+                ),
+                0
+            );
+
+            // Wake both remaining threads at the same time.
+            assert_eq!(
+                libc::os_sync_wake_by_address_all(
+                    ptr::from_ref(futex).cast_mut().cast(),
+                    size_of::<i32>(),
+                    libc::OS_SYNC_WAKE_BY_ADDRESS_NONE,
+                ),
+                0
+            );
+        }
+    })
+}
+
+fn param_mismatch() {
+    let futex = 0;
+    thread::scope(|s| {
+        s.spawn(|| {
+            unsafe {
+                assert_eq!(
+                    libc::os_sync_wait_on_address_with_timeout(
+                        ptr::from_ref(&futex).cast_mut().cast(),
+                        0,
+                        size_of::<i32>(),
+                        libc::OS_SYNC_WAIT_ON_ADDRESS_NONE,
+                        libc::OS_CLOCK_MACH_ABSOLUTE_TIME,
+                        400_000_000,
+                    ),
+                    -1,
+                );
+                assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT);
+            }
+        });
+
+        s.spawn(|| {
+            thread::yield_now();
+            unsafe {
+                assert_eq!(
+                    libc::os_sync_wait_on_address(
+                        ptr::from_ref(&futex).cast_mut().cast(),
+                        0,
+                        size_of::<i32>(),
+                        libc::OS_SYNC_WAIT_ON_ADDRESS_SHARED,
+                    ),
+                    -1,
+                );
+                // This call fails because it uses the shared flag whereas the first waiter didn't.
+                assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
+            }
+        });
+
+        thread::yield_now();
+
+        unsafe {
+            assert_eq!(
+                libc::os_sync_wake_by_address_any(
+                    ptr::from_ref(&futex).cast_mut().cast(),
+                    size_of::<i32>(),
+                    libc::OS_SYNC_WAIT_ON_ADDRESS_SHARED,
+                ),
+                -1,
+            );
+            // This call fails because it uses the shared flag whereas the waiter didn't.
+            assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
+        }
+    });
+}
+
+fn main() {
+    wake_nobody();
+    wake_dangling();
+    wait_wrong_val();
+    wait_timeout();
+    wait_absolute_timeout();
+    wait_wake();
+    wait_wake_multiple();
+    param_mismatch();
+}
diff --git a/src/tools/miri/tests/pass-dep/getrandom.rs b/src/tools/miri/tests/pass-dep/getrandom.rs
index a5bc5ec7079..d359730e7f9 100644
--- a/src/tools/miri/tests/pass-dep/getrandom.rs
+++ b/src/tools/miri/tests/pass-dep/getrandom.rs
@@ -3,7 +3,7 @@
 //@revisions: isolation no_isolation
 //@[no_isolation]compile-flags: -Zmiri-disable-isolation
 
-/// Test direct calls of getrandom 0.1 and 0.2.
+/// Test direct calls of getrandom 0.1, 0.2 and 0.3.
 fn main() {
     let mut data = vec![0; 16];
 
@@ -13,4 +13,6 @@ fn main() {
     getrandom_01::getrandom(&mut data).unwrap();
 
     getrandom_02::getrandom(&mut data).unwrap();
+
+    getrandom_03::fill(&mut data).unwrap();
 }
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
index 23e2122ee50..dc3ab2828fa 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
@@ -230,10 +230,10 @@ fn test_two_same_fd_in_same_epoll_instance() {
     //Two notification should be received.
     let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
     let expected_value = 5 as u64;
-    check_epoll_wait::<8>(epfd, &[
-        (expected_event, expected_value),
-        (expected_event, expected_value),
-    ]);
+    check_epoll_wait::<8>(
+        epfd,
+        &[(expected_event, expected_value), (expected_event, expected_value)],
+    );
 }
 
 fn test_epoll_eventfd() {
@@ -290,10 +290,10 @@ fn test_epoll_socketpair_both_sides() {
     let expected_value0 = fds[0] as u64;
     let expected_event1 = u32::try_from(libc::EPOLLOUT).unwrap();
     let expected_value1 = fds[1] as u64;
-    check_epoll_wait::<8>(epfd, &[
-        (expected_event0, expected_value0),
-        (expected_event1, expected_value1),
-    ]);
+    check_epoll_wait::<8>(
+        epfd,
+        &[(expected_event0, expected_value0), (expected_event1, expected_value1)],
+    );
 
     // Read from fds[0].
     let mut buf: [u8; 5] = [0; 5];
@@ -453,10 +453,10 @@ fn test_socketpair_read() {
     let expected_value0 = fds[0] as u64;
     let expected_event1 = u32::try_from(libc::EPOLLOUT).unwrap();
     let expected_value1 = fds[1] as u64;
-    check_epoll_wait::<8>(epfd, &[
-        (expected_event0, expected_value0),
-        (expected_event1, expected_value1),
-    ]);
+    check_epoll_wait::<8>(
+        epfd,
+        &[(expected_event0, expected_value0), (expected_event1, expected_value1)],
+    );
 
     // Read 3 bytes from fds[0].
     let mut buf: [u8; 3] = [0; 3];
diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs
index 61410f7c4e0..f100c4d6a86 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.rs
+++ b/src/tools/miri/tests/pass/dyn-upcast.rs
@@ -10,6 +10,8 @@ fn main() {
     replace_vptr();
     vtable_nop_cast();
     drop_principal();
+    modulo_binder();
+    modulo_assoc();
 }
 
 fn vtable_nop_cast() {
@@ -482,3 +484,53 @@ fn drop_principal() {
     println!("before");
     drop(y);
 }
+
+// Test for <https://github.com/rust-lang/rust/issues/135316>.
+fn modulo_binder() {
+    trait Supertrait<T> {
+        fn _print_numbers(&self, mem: &[usize; 100]) {
+            println!("{mem:?}");
+        }
+    }
+    impl<T> Supertrait<T> for () {}
+
+    trait Trait<T, U>: Supertrait<T> + Supertrait<U> {
+        fn say_hello(&self, _: &usize) {
+            println!("Hello!");
+        }
+    }
+    impl<T, U> Trait<T, U> for () {}
+
+    (&() as &'static dyn for<'a> Trait<&'static (), &'a ()>
+        as &'static dyn Trait<&'static (), &'static ()>)
+        .say_hello(&0);
+}
+
+// Test for <https://github.com/rust-lang/rust/issues/135315>.
+fn modulo_assoc() {
+    trait Supertrait<T> {
+        fn _print_numbers(&self, mem: &[usize; 100]) {
+            println!("{mem:?}");
+        }
+    }
+    impl<T> Supertrait<T> for () {}
+
+    trait Identity {
+        type Selff;
+    }
+    impl<Selff> Identity for Selff {
+        type Selff = Selff;
+    }
+
+    trait Middle<T>: Supertrait<()> + Supertrait<T> {
+        fn say_hello(&self, _: &usize) {
+            println!("Hello!");
+        }
+    }
+    impl<T> Middle<T> for () {}
+
+    trait Trait: Middle<<() as Identity>::Selff> {}
+    impl Trait for () {}
+
+    (&() as &dyn Trait as &dyn Middle<()>).say_hello(&0);
+}
diff --git a/src/tools/miri/tests/pass/dyn-upcast.stdout b/src/tools/miri/tests/pass/dyn-upcast.stdout
index edd99a114a1..379600db3d9 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.stdout
+++ b/src/tools/miri/tests/pass/dyn-upcast.stdout
@@ -2,3 +2,5 @@ before
 goodbye
 before
 goodbye
+Hello!
+Hello!
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 4de315e3589..2f4f64b1aa8 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -31,6 +31,7 @@ fn main() {
     test_fast();
     test_algebraic();
     test_fmuladd();
+    test_min_max_nondet();
 }
 
 trait Float: Copy + PartialEq + Debug {
@@ -1211,3 +1212,30 @@ fn test_fmuladd() {
     test_operations_f32(0.1, 0.2, 0.3);
     test_operations_f64(1.1, 1.2, 1.3);
 }
+
+/// `min` and `max` on equal arguments are non-deterministic.
+fn test_min_max_nondet() {
+    /// Ensure that if we call the closure often enough, we see both `true` and `false.`
+    #[track_caller]
+    fn ensure_both(f: impl Fn() -> bool) {
+        let rounds = 16;
+        let first = f();
+        for _ in 1..rounds {
+            if f() != first {
+                // We saw two different values!
+                return;
+            }
+        }
+        // We saw the same thing N times.
+        panic!("expected non-determinism, got {rounds} times the same result: {first:?}");
+    }
+
+    ensure_both(|| f16::min(0.0, -0.0).is_sign_positive());
+    ensure_both(|| f16::max(0.0, -0.0).is_sign_positive());
+    ensure_both(|| f32::min(0.0, -0.0).is_sign_positive());
+    ensure_both(|| f32::max(0.0, -0.0).is_sign_positive());
+    ensure_both(|| f64::min(0.0, -0.0).is_sign_positive());
+    ensure_both(|| f64::max(0.0, -0.0).is_sign_positive());
+    ensure_both(|| f128::min(0.0, -0.0).is_sign_positive());
+    ensure_both(|| f128::max(0.0, -0.0).is_sign_positive());
+}
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index 9b9542b88a9..3bc953c3a5f 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -13,7 +13,7 @@ use ui_test::custom_flags::edition::Edition;
 use ui_test::dependencies::DependencyBuilder;
 use ui_test::per_test_config::TestConfig;
 use ui_test::spanned::Spanned;
-use ui_test::{CommandBuilder, Config, Format, Match, OutputConflictHandling, status_emitter};
+use ui_test::{CommandBuilder, Config, Format, Match, ignore_output_conflict, status_emitter};
 
 #[derive(Copy, Clone, Debug)]
 enum Mode {
@@ -82,9 +82,18 @@ fn build_native_lib() -> PathBuf {
     native_lib_path
 }
 
+struct WithDependencies {
+    bless: bool,
+}
+
 /// 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 {
+fn miri_config(
+    target: &str,
+    path: &str,
+    mode: Mode,
+    with_dependencies: Option<WithDependencies>,
+) -> 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();
@@ -119,22 +128,26 @@ fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
     // keep in sync with `./miri run`
     config.comment_defaults.base().add_custom("edition", Edition("2021".into()));
 
-    if with_dependencies {
-        config.comment_defaults.base().set_custom("dependencies", DependencyBuilder {
-            program: CommandBuilder {
-                // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary.
-                // (It's a separate crate, so we don't get an env var from cargo.)
-                program: miri_path()
-                    .with_file_name(format!("cargo-miri{}", env::consts::EXE_SUFFIX)),
-                // There is no `cargo miri build` so we just use `cargo miri run`.
-                args: ["miri", "run"].into_iter().map(Into::into).collect(),
-                // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>.
-                envs: vec![("RUSTFLAGS".into(), None)],
-                ..CommandBuilder::cargo()
+    if let Some(WithDependencies { bless }) = with_dependencies {
+        config.comment_defaults.base().set_custom(
+            "dependencies",
+            DependencyBuilder {
+                program: CommandBuilder {
+                    // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary.
+                    // (It's a separate crate, so we don't get an env var from cargo.)
+                    program: miri_path()
+                        .with_file_name(format!("cargo-miri{}", env::consts::EXE_SUFFIX)),
+                    // There is no `cargo miri build` so we just use `cargo miri run`.
+                    args: ["miri", "run"].into_iter().map(Into::into).collect(),
+                    // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>.
+                    envs: vec![("RUSTFLAGS".into(), None)],
+                    ..CommandBuilder::cargo()
+                },
+                crate_manifest_path: Path::new("test_dependencies").join("Cargo.toml"),
+                build_std: None,
+                bless_lockfile: bless,
             },
-            crate_manifest_path: Path::new("test_dependencies").join("Cargo.toml"),
-            build_std: None,
-        });
+        );
     }
     config
 }
@@ -146,7 +159,20 @@ fn run_tests(
     with_dependencies: bool,
     tmpdir: &Path,
 ) -> Result<()> {
+    // Handle command-line arguments.
+    let mut args = ui_test::Args::test()?;
+    args.bless |= env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
+
+    let with_dependencies = with_dependencies.then_some(WithDependencies { bless: args.bless });
+
     let mut config = miri_config(target, path, mode, with_dependencies);
+    config.with_args(&args);
+    config.bless_command = Some("./miri test --bless".into());
+
+    if env::var_os("MIRI_SKIP_UI_CHECKS").is_some() {
+        assert!(!args.bless, "cannot use RUSTC_BLESS and MIRI_SKIP_UI_CHECKS at the same time");
+        config.output_conflict_handling = ignore_output_conflict;
+    }
 
     // Add a test env var to do environment communication tests.
     config.program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into())));
@@ -182,16 +208,6 @@ fn run_tests(
         config.program.args.push(flag);
     }
 
-    // Handle command-line arguments.
-    let mut args = ui_test::Args::test()?;
-    args.bless |= env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
-    config.with_args(&args);
-    config.bless_command = Some("./miri test --bless".into());
-
-    if env::var_os("MIRI_SKIP_UI_CHECKS").is_some() {
-        assert!(!args.bless, "cannot use RUSTC_BLESS and MIRI_SKIP_UI_CHECKS at the same time");
-        config.output_conflict_handling = OutputConflictHandling::Ignore;
-    }
     eprintln!("   Compiler: {}", config.program.display());
     ui_test::run_tests_generic(
         // Only run one test suite. In the future we can add all test suites to one `Vec` and run
@@ -327,7 +343,8 @@ fn main() -> Result<()> {
 }
 
 fn run_dep_mode(target: String, args: impl Iterator<Item = OsString>) -> Result<()> {
-    let mut config = miri_config(&target, "", Mode::RunDep, /* with dependencies */ true);
+    let mut config =
+        miri_config(&target, "", Mode::RunDep, Some(WithDependencies { bless: false }));
     config.comment_defaults.base().custom.remove("edition"); // `./miri` adds an `--edition` in `args`, so don't set it twice
     config.fill_host_and_target()?;
     config.program.args = args.collect();
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index 04de3493ea2..565721a9093 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -148,16 +148,6 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
 
             let is_aarch64 = target_triple.starts_with("aarch64");
 
-            let skip_tests = if is_aarch64 {
-                vec![
-                    // Those tests fail only inside of Docker on aarch64, as of December 2024
-                    "tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs".to_string(),
-                    "tests/ui/consts/large_const_alloc.rs".to_string(),
-                ]
-            } else {
-                vec![]
-            };
-
             let checkout_dir = Utf8PathBuf::from("/checkout");
             let env = EnvironmentBuilder::default()
                 .host_tuple(target_triple)
@@ -169,7 +159,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .shared_llvm(true)
                 // FIXME: Enable bolt for aarch64 once it's fixed upstream. Broken as of December 2024.
                 .use_bolt(!is_aarch64)
-                .skipped_tests(skip_tests)
+                .skipped_tests(vec![])
                 .build()?;
 
             (env, shared.build_args)
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index b4dc753ab53..70a72bd1abe 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -388,9 +388,13 @@ impl CompletedProcess {
         self
     }
 
+    /// Check the **exit status** of the process. On Unix, this is *not* the **wait status**.
+    ///
+    /// See [`std::process::ExitStatus::code`]. This is not to be confused with
+    /// [`std::process::ExitCode`].
     #[track_caller]
     pub fn assert_exit_code(&self, code: i32) -> &Self {
-        assert!(self.output.status.code() == Some(code));
+        assert_eq!(self.output.status.code(), Some(code));
         self
     }
 }
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index 8894ea7fb20..8d99924a2d1 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -1,5 +1,6 @@
 use std::ffi::{OsStr, OsString};
-use std::path::Path;
+use std::path::{Path, PathBuf};
+use std::str::FromStr as _;
 
 use crate::command::Command;
 use crate::env::env_var;
@@ -215,6 +216,18 @@ impl Rustc {
         self
     }
 
+    /// Specify option of `-C symbol-mangling-version`.
+    pub fn symbol_mangling_version(&mut self, option: &str) -> &mut Self {
+        self.cmd.arg(format!("-Csymbol-mangling-version={option}"));
+        self
+    }
+
+    /// Specify `-C prefer-dynamic`.
+    pub fn prefer_dynamic(&mut self) -> &mut Self {
+        self.cmd.arg(format!("-Cprefer-dynamic"));
+        self
+    }
+
     /// Specify error format to use
     pub fn error_format(&mut self, format: &str) -> &mut Self {
         self.cmd.arg(format!("--error-format={format}"));
@@ -390,3 +403,10 @@ impl Rustc {
         self
     }
 }
+
+/// Query the sysroot path corresponding `rustc --print=sysroot`.
+#[track_caller]
+pub fn sysroot() -> PathBuf {
+    let path = rustc().print("sysroot").run().stdout_utf8();
+    PathBuf::from_str(path.trim()).unwrap()
+}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 7316244b384..a8c9bec57fd 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -47,7 +47,9 @@ pub use wasmparser;
 // tidy-alphabetical-end
 
 // Re-exports of external dependencies.
-pub use external_deps::{c_build, c_cxx_compiler, clang, htmldocck, llvm, python, rustc, rustdoc};
+pub use external_deps::{
+    cargo, c_build, c_cxx_compiler, clang, htmldocck, llvm, python, rustc, rustdoc
+};
 
 // These rely on external dependencies.
 pub use c_cxx_compiler::{Cc, Gcc, cc, cxx, extra_c_flags, extra_cxx_flags, gcc};
@@ -79,7 +81,10 @@ pub use env::{env_var, env_var_os, set_current_dir};
 pub use run::{cmd, run, run_fail, run_with_args};
 
 /// Helpers for checking target information.
-pub use targets::{is_aix, is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os};
+pub use targets::{
+    apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, llvm_components_contain,
+    target, uname,
+};
 
 /// Helpers for building names of output artifacts that are potentially target-specific.
 pub use artifact_names::{
@@ -104,4 +109,3 @@ pub use assertion_helpers::{
 pub use string::{
     count_regex_matches_in_files_with_extension, invalid_utf8_contains, invalid_utf8_not_contains,
 };
-use crate::external_deps::cargo;
diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/symbols.rs
index fd0c866bcc9..e4d244e14a4 100644
--- a/src/tools/run-make-support/src/symbols.rs
+++ b/src/tools/run-make-support/src/symbols.rs
@@ -2,28 +2,44 @@ use std::path::Path;
 
 use object::{self, Object, ObjectSymbol, SymbolIterator};
 
-/// Iterate through the symbols in an object file.
-///
-/// Uses a callback because `SymbolIterator` does not own its data.
+/// Given an [`object::File`], find the exported dynamic symbol names via
+/// [`object::Object::exports`]. This does not distinguish between which section the symbols appear
+/// in.
+#[track_caller]
+pub fn exported_dynamic_symbol_names<'file>(file: &'file object::File<'file>) -> Vec<&'file str> {
+    file.exports()
+        .unwrap()
+        .into_iter()
+        .filter_map(|sym| std::str::from_utf8(sym.name()).ok())
+        .collect()
+}
+
+/// Iterate through the symbols in an object file. See [`object::Object::symbols`].
 ///
-/// Panics if `path` is not a valid object file readable by the current user.
+/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be
+/// parsed as a recognized object file.
+#[track_caller]
 pub fn with_symbol_iter<P, F, R>(path: P, func: F) -> R
 where
     P: AsRef<Path>,
     F: FnOnce(&mut SymbolIterator<'_, '_>) -> R,
 {
-    let raw_bytes = crate::fs::read(path);
-    let f = object::File::parse(raw_bytes.as_slice()).expect("unable to parse file");
+    let path = path.as_ref();
+    let blob = crate::fs::read(path);
+    let f = object::File::parse(&*blob)
+        .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
     let mut iter = f.symbols();
     func(&mut iter)
 }
 
 /// Check an object file's symbols for substrings.
 ///
-/// Returns `true` if any of the symbols found in the object file at
-/// `path` contain a substring listed in `substrings`.
+/// Returns `true` if any of the symbols found in the object file at `path` contain a substring
+/// listed in `substrings`.
 ///
-/// Panics if `path` is not a valid object file readable by the current user.
+/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be
+/// parsed as a recognized object file.
+#[track_caller]
 pub fn any_symbol_contains(path: impl AsRef<Path>, substrings: &[&str]) -> bool {
     with_symbol_iter(path, |syms| {
         for sym in syms {
diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs
index ae004fd0cbd..a16fca71d2e 100644
--- a/src/tools/run-make-support/src/targets.rs
+++ b/src/tools/run-make-support/src/targets.rs
@@ -22,6 +22,12 @@ pub fn is_msvc() -> bool {
     target().contains("msvc")
 }
 
+/// Check if target is windows-gnu.
+#[must_use]
+pub fn is_windows_gnu() -> bool {
+    target().ends_with("windows-gnu")
+}
+
 /// Check if target uses macOS.
 #[must_use]
 pub fn is_darwin() -> bool {
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index f92668a6a97..2dfca7c4803 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -846,7 +846,6 @@ dependencies = [
  "dashmap",
  "hashbrown",
  "rustc-hash 2.0.0",
- "sptr",
  "triomphe",
 ]
 
@@ -1928,12 +1927,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "sptr"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
-
-[[package]]
 name = "stdx"
 version = "0.0.0"
 dependencies = [
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 1029844cd3a..c42ae171d86 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
 resolver = "2"
 
 [workspace.package]
-rust-version = "1.83"
+rust-version = "1.84"
 edition = "2021"
 license = "MIT OR Apache-2.0"
 authors = ["rust-analyzer team"]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 1327bb3ab59..16c7b5ca00a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -1381,6 +1381,9 @@ impl ExprCollector<'_> {
                 }
             }
             ast::Stmt::Item(ast::Item::MacroDef(macro_)) => {
+                if self.check_cfg(&macro_).is_none() {
+                    return;
+                }
                 let Some(name) = macro_.name() else {
                     statements.push(Statement::Item(Item::Other));
                     return;
@@ -1390,6 +1393,9 @@ impl ExprCollector<'_> {
                 self.collect_macro_def(statements, macro_id);
             }
             ast::Stmt::Item(ast::Item::MacroRules(macro_)) => {
+                if self.check_cfg(&macro_).is_none() {
+                    return;
+                }
                 let Some(name) = macro_.name() else {
                     statements.push(Statement::Item(Item::Other));
                     return;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
index f483efa8517..e136dd18a55 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
@@ -475,7 +475,7 @@ fn outer() {
 
             block scope::tests
             name: _
-            outer: v
+            outer: vg
 
             crate
             outer: v
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index 5d67902c8ac..c30ad0163b9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -445,6 +445,10 @@ fn find_in_dep(
         };
         cov_mark::hit!(partially_imported);
         if info.is_unstable {
+            if !ctx.cfg.allow_unstable {
+                // the item is unstable and we are not allowed to use unstable items
+                continue;
+            }
             choice.stability = Unstable;
         }
 
@@ -670,6 +674,7 @@ mod tests {
         prefer_prelude: bool,
         prefer_absolute: bool,
         prefer_no_std: bool,
+        allow_unstable: bool,
         expect: Expect,
     ) {
         let (db, pos) = TestDB::with_position(ra_fixture);
@@ -711,7 +716,7 @@ mod tests {
                 module,
                 prefix,
                 ignore_local_imports,
-                ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute },
+                ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute, allow_unstable },
             );
             format_to!(
                 res,
@@ -732,7 +737,7 @@ mod tests {
         path: &str,
         expect: Expect,
     ) {
-        check_found_path_(ra_fixture, path, false, false, false, expect);
+        check_found_path_(ra_fixture, path, false, false, false, false, expect);
     }
 
     fn check_found_path_prelude(
@@ -740,7 +745,7 @@ mod tests {
         path: &str,
         expect: Expect,
     ) {
-        check_found_path_(ra_fixture, path, true, false, false, expect);
+        check_found_path_(ra_fixture, path, true, false, false, false, expect);
     }
 
     fn check_found_path_absolute(
@@ -748,7 +753,7 @@ mod tests {
         path: &str,
         expect: Expect,
     ) {
-        check_found_path_(ra_fixture, path, false, true, false, expect);
+        check_found_path_(ra_fixture, path, false, true, false, false, expect);
     }
 
     fn check_found_path_prefer_no_std(
@@ -756,7 +761,15 @@ mod tests {
         path: &str,
         expect: Expect,
     ) {
-        check_found_path_(ra_fixture, path, false, false, true, expect);
+        check_found_path_(ra_fixture, path, false, false, true, false, expect);
+    }
+
+    fn check_found_path_prefer_no_std_allow_unstable(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        path: &str,
+        expect: Expect,
+    ) {
+        check_found_path_(ra_fixture, path, false, false, true, true, expect);
     }
 
     #[test]
@@ -1951,7 +1964,7 @@ pub mod ops {
 
     #[test]
     fn respect_unstable_modules() {
-        check_found_path_prefer_no_std(
+        check_found_path_prefer_no_std_allow_unstable(
             r#"
 //- /main.rs crate:main deps:std,core
 extern crate std;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index ac262950f13..34635997bdf 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -10,7 +10,6 @@ use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use span::Edition;
 use stdx::{format_to, TupleExt};
-use syntax::ToSmolStr;
 use triomphe::Arc;
 
 use crate::{
@@ -88,9 +87,9 @@ impl ImportMap {
             .iter()
             // We've only collected items, whose name cannot be tuple field so unwrapping is fine.
             .flat_map(|(&item, (info, _))| {
-                info.iter().enumerate().map(move |(idx, info)| {
-                    (item, info.name.unescaped().display(db.upcast()).to_smolstr(), idx as u32)
-                })
+                info.iter()
+                    .enumerate()
+                    .map(move |(idx, info)| (item, info.name.as_str(), idx as u32))
             })
             .collect();
         importables.sort_by(|(_, l_info, _), (_, r_info, _)| {
@@ -168,7 +167,8 @@ impl ImportMap {
                     let attr_id = if let Some(import) = import {
                         match import {
                             ImportOrExternCrate::ExternCrate(id) => Some(id.into()),
-                            ImportOrExternCrate::Import(id) => Some(id.import.into()),
+                            ImportOrExternCrate::Import(id) => Some(id.use_.into()),
+                            ImportOrExternCrate::Glob(id) => Some(id.use_.into()),
                         }
                     } else {
                         match item {
@@ -441,7 +441,7 @@ pub fn search_dependencies(
 }
 
 fn search_maps(
-    db: &dyn DefDatabase,
+    _db: &dyn DefDatabase,
     import_maps: &[Arc<ImportMap>],
     mut stream: fst::map::Union<'_>,
     query: &Query,
@@ -464,11 +464,7 @@ fn search_maps(
                         .then(|| (item, &import_infos[info_idx as usize]))
                 })
                 .filter(|&(_, info)| {
-                    query.search_mode.check(
-                        &query.query,
-                        query.case_sensitive,
-                        &info.name.unescaped().display(db.upcast()).to_smolstr(),
-                    )
+                    query.search_mode.check(&query.query, query.case_sensitive, info.name.as_str())
                 });
             res.extend(iter.map(TupleExt::head));
         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index 0fec7674109..65a39c56561 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -31,21 +31,62 @@ pub struct PerNsGlobImports {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum ImportOrExternCrate {
+    Glob(GlobId),
     Import(ImportId),
     ExternCrate(ExternCrateId),
 }
 
+impl From<ImportOrGlob> for ImportOrExternCrate {
+    fn from(value: ImportOrGlob) -> Self {
+        match value {
+            ImportOrGlob::Glob(it) => ImportOrExternCrate::Glob(it),
+            ImportOrGlob::Import(it) => ImportOrExternCrate::Import(it),
+        }
+    }
+}
+
+impl ImportOrExternCrate {
+    pub fn import_or_glob(self) -> Option<ImportOrGlob> {
+        match self {
+            ImportOrExternCrate::Import(it) => Some(ImportOrGlob::Import(it)),
+            ImportOrExternCrate::Glob(it) => Some(ImportOrGlob::Glob(it)),
+            _ => None,
+        }
+    }
+
+    pub fn import(self) -> Option<ImportId> {
+        match self {
+            ImportOrExternCrate::Import(it) => Some(it),
+            _ => None,
+        }
+    }
+
+    pub fn glob(self) -> Option<GlobId> {
+        match self {
+            ImportOrExternCrate::Glob(id) => Some(id),
+            _ => None,
+        }
+    }
+
+    pub fn use_(self) -> Option<UseId> {
+        match self {
+            ImportOrExternCrate::Glob(id) => Some(id.use_),
+            ImportOrExternCrate::Import(id) => Some(id.use_),
+            _ => None,
+        }
+    }
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub(crate) enum ImportType {
+pub enum ImportOrGlob {
+    Glob(GlobId),
     Import(ImportId),
-    Glob(UseId),
-    ExternCrate(ExternCrateId),
 }
 
-impl ImportOrExternCrate {
+impl ImportOrGlob {
     pub fn into_import(self) -> Option<ImportId> {
         match self {
-            ImportOrExternCrate::Import(it) => Some(it),
+            ImportOrGlob::Import(it) => Some(it),
             _ => None,
         }
     }
@@ -54,12 +95,39 @@ impl ImportOrExternCrate {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum ImportOrDef {
     Import(ImportId),
+    Glob(GlobId),
     ExternCrate(ExternCrateId),
     Def(ModuleDefId),
 }
+
+impl From<ImportOrExternCrate> for ImportOrDef {
+    fn from(value: ImportOrExternCrate) -> Self {
+        match value {
+            ImportOrExternCrate::Import(it) => ImportOrDef::Import(it),
+            ImportOrExternCrate::Glob(it) => ImportOrDef::Glob(it),
+            ImportOrExternCrate::ExternCrate(it) => ImportOrDef::ExternCrate(it),
+        }
+    }
+}
+
+impl From<ImportOrGlob> for ImportOrDef {
+    fn from(value: ImportOrGlob) -> Self {
+        match value {
+            ImportOrGlob::Import(it) => ImportOrDef::Import(it),
+            ImportOrGlob::Glob(it) => ImportOrDef::Glob(it),
+        }
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct ImportId {
-    pub import: UseId,
+    pub use_: UseId,
+    pub idx: Idx<ast::UseTree>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub struct GlobId {
+    pub use_: UseId,
     pub idx: Idx<ast::UseTree>,
 }
 
@@ -96,8 +164,8 @@ pub struct ItemScope {
 
     // the resolutions of the imports of this scope
     use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
-    use_imports_values: FxHashMap<ImportId, ImportOrDef>,
-    use_imports_macros: FxHashMap<ImportId, ImportOrDef>,
+    use_imports_values: FxHashMap<ImportOrGlob, ImportOrDef>,
+    use_imports_macros: FxHashMap<ImportOrGlob, ImportOrDef>,
 
     use_decls: Vec<UseId>,
     extern_crate_decls: Vec<ExternCrateId>,
@@ -162,7 +230,7 @@ impl ItemScope {
             .map(move |name| (name, self.get(name)))
     }
 
-    pub fn values(&self) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportId>)> + '_ {
+    pub fn values(&self) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportOrGlob>)> + '_ {
         self.values.iter().map(|(n, &i)| (n, i))
     }
 
@@ -172,7 +240,7 @@ impl ItemScope {
         self.types.iter().map(|(n, &i)| (n, i))
     }
 
-    pub fn macros(&self) -> impl Iterator<Item = (&Name, Item<MacroId, ImportId>)> + '_ {
+    pub fn macros(&self) -> impl Iterator<Item = (&Name, Item<MacroId, ImportOrGlob>)> + '_ {
         self.macros.iter().map(|(n, &i)| (n, i))
     }
 
@@ -180,9 +248,10 @@ impl ItemScope {
         self.use_imports_types
             .keys()
             .copied()
-            .filter_map(ImportOrExternCrate::into_import)
+            .filter_map(ImportOrExternCrate::import_or_glob)
             .chain(self.use_imports_values.keys().copied())
             .chain(self.use_imports_macros.keys().copied())
+            .filter_map(ImportOrGlob::into_import)
             .sorted()
             .dedup()
     }
@@ -192,10 +261,10 @@ impl ItemScope {
 
         let mut def_map;
         let mut scope = self;
-        while let Some(&m) = scope.use_imports_macros.get(&import) {
+        while let Some(&m) = scope.use_imports_macros.get(&ImportOrGlob::Import(import)) {
             match m {
                 ImportOrDef::Import(i) => {
-                    let module_id = i.import.lookup(db).container;
+                    let module_id = i.use_.lookup(db).container;
                     def_map = module_id.def_map(db);
                     scope = &def_map[module_id.local_id].scope;
                     import = i;
@@ -211,7 +280,7 @@ impl ItemScope {
         while let Some(&m) = scope.use_imports_types.get(&ImportOrExternCrate::Import(import)) {
             match m {
                 ImportOrDef::Import(i) => {
-                    let module_id = i.import.lookup(db).container;
+                    let module_id = i.use_.lookup(db).container;
                     def_map = module_id.def_map(db);
                     scope = &def_map[module_id.local_id].scope;
                     import = i;
@@ -224,10 +293,10 @@ impl ItemScope {
             }
         }
         let mut scope = self;
-        while let Some(&m) = scope.use_imports_values.get(&import) {
+        while let Some(&m) = scope.use_imports_values.get(&ImportOrGlob::Import(import)) {
             match m {
                 ImportOrDef::Import(i) => {
-                    let module_id = i.import.lookup(db).container;
+                    let module_id = i.use_.lookup(db).container;
                     def_map = module_id.def_map(db);
                     scope = &def_map[module_id.local_id].scope;
                     import = i;
@@ -488,9 +557,13 @@ impl ItemScope {
         self.unnamed_trait_imports.get(&tr).map(|trait_| trait_.vis)
     }
 
-    pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
-        // FIXME: import
-        self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import: None });
+    pub(crate) fn push_unnamed_trait(
+        &mut self,
+        tr: TraitId,
+        vis: Visibility,
+        import: Option<ImportId>,
+    ) {
+        self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import });
     }
 
     pub(crate) fn push_res_with_import(
@@ -498,7 +571,7 @@ impl ItemScope {
         glob_imports: &mut PerNsGlobImports,
         lookup: (LocalModuleId, Name),
         def: PerNs,
-        import: Option<ImportType>,
+        import: Option<ImportOrExternCrate>,
     ) -> bool {
         let mut changed = false;
 
@@ -509,41 +582,22 @@ impl ItemScope {
             match existing {
                 Entry::Vacant(entry) => {
                     match import {
-                        Some(ImportType::Glob(_)) => {
+                        Some(ImportOrExternCrate::Glob(_)) => {
                             glob_imports.types.insert(lookup.clone());
                         }
                         _ => _ = glob_imports.types.remove(&lookup),
                     }
-                    let import = match import {
-                        Some(ImportType::ExternCrate(extern_crate)) => {
-                            Some(ImportOrExternCrate::ExternCrate(extern_crate))
-                        }
-                        Some(ImportType::Import(import)) => {
-                            Some(ImportOrExternCrate::Import(import))
-                        }
-                        None | Some(ImportType::Glob(_)) => None,
-                    };
                     let prev = std::mem::replace(&mut fld.import, import);
                     if let Some(import) = import {
-                        self.use_imports_types.insert(
-                            import,
-                            match prev {
-                                Some(ImportOrExternCrate::Import(import)) => {
-                                    ImportOrDef::Import(import)
-                                }
-                                Some(ImportOrExternCrate::ExternCrate(import)) => {
-                                    ImportOrDef::ExternCrate(import)
-                                }
-                                None => ImportOrDef::Def(fld.def),
-                            },
-                        );
+                        self.use_imports_types
+                            .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
                     }
                     entry.insert(fld);
                     changed = true;
                 }
                 Entry::Occupied(mut entry) => {
                     match import {
-                        Some(ImportType::Glob(..)) => {
+                        Some(ImportOrExternCrate::Glob(..)) => {
                             // Multiple globs may import the same item and they may
                             // override visibility from previously resolved globs. This is
                             // currently handled by `DefCollector`, because we need to
@@ -552,28 +606,11 @@ impl ItemScope {
                         }
                         _ => {
                             if glob_imports.types.remove(&lookup) {
-                                let import = match import {
-                                    Some(ImportType::ExternCrate(extern_crate)) => {
-                                        Some(ImportOrExternCrate::ExternCrate(extern_crate))
-                                    }
-                                    Some(ImportType::Import(import)) => {
-                                        Some(ImportOrExternCrate::Import(import))
-                                    }
-                                    None | Some(ImportType::Glob(_)) => None,
-                                };
                                 let prev = std::mem::replace(&mut fld.import, import);
                                 if let Some(import) = import {
                                     self.use_imports_types.insert(
                                         import,
-                                        match prev {
-                                            Some(ImportOrExternCrate::Import(import)) => {
-                                                ImportOrDef::Import(import)
-                                            }
-                                            Some(ImportOrExternCrate::ExternCrate(import)) => {
-                                                ImportOrDef::ExternCrate(import)
-                                            }
-                                            None => ImportOrDef::Def(fld.def),
-                                        },
+                                        prev.map_or(ImportOrDef::Def(fld.def), Into::into),
                                     );
                                 }
                                 cov_mark::hit!(import_shadowed);
@@ -591,44 +628,31 @@ impl ItemScope {
             match existing {
                 Entry::Vacant(entry) => {
                     match import {
-                        Some(ImportType::Glob(_)) => {
+                        Some(ImportOrExternCrate::Glob(_)) => {
                             glob_imports.values.insert(lookup.clone());
                         }
                         _ => _ = glob_imports.values.remove(&lookup),
                     }
-                    let import = match import {
-                        Some(ImportType::Import(import)) => Some(import),
-                        _ => None,
-                    };
+                    let import = import.and_then(ImportOrExternCrate::import_or_glob);
                     let prev = std::mem::replace(&mut fld.import, import);
                     if let Some(import) = import {
-                        self.use_imports_values.insert(
-                            import,
-                            match prev {
-                                Some(import) => ImportOrDef::Import(import),
-                                None => ImportOrDef::Def(fld.def),
-                            },
-                        );
+                        self.use_imports_values
+                            .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
                     }
                     entry.insert(fld);
                     changed = true;
                 }
-                Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+                Entry::Occupied(mut entry)
+                    if !matches!(import, Some(ImportOrExternCrate::Glob(..))) =>
+                {
                     if glob_imports.values.remove(&lookup) {
                         cov_mark::hit!(import_shadowed);
-                        let import = match import {
-                            Some(ImportType::Import(import)) => Some(import),
-                            _ => None,
-                        };
+
+                        let import = import.and_then(ImportOrExternCrate::import_or_glob);
                         let prev = std::mem::replace(&mut fld.import, import);
                         if let Some(import) = import {
-                            self.use_imports_values.insert(
-                                import,
-                                match prev {
-                                    Some(import) => ImportOrDef::Import(import),
-                                    None => ImportOrDef::Def(fld.def),
-                                },
-                            );
+                            self.use_imports_values
+                                .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
                         }
                         entry.insert(fld);
                         changed = true;
@@ -643,43 +667,33 @@ impl ItemScope {
             match existing {
                 Entry::Vacant(entry) => {
                     match import {
-                        Some(ImportType::Glob(_)) => {
+                        Some(ImportOrExternCrate::Glob(_)) => {
                             glob_imports.macros.insert(lookup.clone());
                         }
                         _ => _ = glob_imports.macros.remove(&lookup),
                     }
-                    let import = match import {
-                        Some(ImportType::Import(import)) => Some(import),
-                        _ => None,
-                    };
+                    let import = import.and_then(ImportOrExternCrate::import_or_glob);
                     let prev = std::mem::replace(&mut fld.import, import);
                     if let Some(import) = import {
                         self.use_imports_macros.insert(
                             import,
-                            match prev {
-                                Some(import) => ImportOrDef::Import(import),
-                                None => ImportOrDef::Def(fld.def.into()),
-                            },
+                            prev.map_or_else(|| ImportOrDef::Def(fld.def.into()), Into::into),
                         );
                     }
                     entry.insert(fld);
                     changed = true;
                 }
-                Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+                Entry::Occupied(mut entry)
+                    if !matches!(import, Some(ImportOrExternCrate::Glob(..))) =>
+                {
                     if glob_imports.macros.remove(&lookup) {
                         cov_mark::hit!(import_shadowed);
-                        let import = match import {
-                            Some(ImportType::Import(import)) => Some(import),
-                            _ => None,
-                        };
+                        let import = import.and_then(ImportOrExternCrate::import_or_glob);
                         let prev = std::mem::replace(&mut fld.import, import);
                         if let Some(import) = import {
                             self.use_imports_macros.insert(
                                 import,
-                                match prev {
-                                    Some(import) => ImportOrDef::Import(import),
-                                    None => ImportOrDef::Def(fld.def.into()),
-                                },
+                                prev.map_or_else(|| ImportOrDef::Def(fld.def.into()), Into::into),
                             );
                         }
                         entry.insert(fld);
@@ -704,16 +718,27 @@ impl ItemScope {
             .map(|def| &mut def.vis)
             .chain(self.values.values_mut().map(|def| &mut def.vis))
             .chain(self.unnamed_trait_imports.values_mut().map(|def| &mut def.vis))
-            .for_each(|vis| {
-                *vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
+            .for_each(|vis| match vis {
+                &mut Visibility::Module(_, visibility_explicitness) => {
+                    *vis = Visibility::Module(this_module, visibility_explicitness)
+                }
+                Visibility::Public => {
+                    *vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
+                }
             });
 
         for mac in self.macros.values_mut() {
             if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) {
                 continue;
             }
-
-            mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit);
+            match mac.vis {
+                Visibility::Module(_, visibility_explicitness) => {
+                    mac.vis = Visibility::Module(this_module, visibility_explicitness)
+                }
+                Visibility::Public => {
+                    mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
+                }
+            }
         }
     }
 
@@ -732,20 +757,25 @@ impl ItemScope {
                 buf.push_str(" t");
                 match import {
                     Some(ImportOrExternCrate::Import(_)) => buf.push('i'),
+                    Some(ImportOrExternCrate::Glob(_)) => buf.push('g'),
                     Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'),
                     None => (),
                 }
             }
             if let Some(Item { import, .. }) = def.values {
                 buf.push_str(" v");
-                if import.is_some() {
-                    buf.push('i');
+                match import {
+                    Some(ImportOrGlob::Import(_)) => buf.push('i'),
+                    Some(ImportOrGlob::Glob(_)) => buf.push('g'),
+                    None => (),
                 }
             }
             if let Some(Item { import, .. }) = def.macros {
                 buf.push_str(" m");
-                if import.is_some() {
-                    buf.push('i');
+                match import {
+                    Some(ImportOrGlob::Import(_)) => buf.push('i'),
+                    Some(ImportOrGlob::Glob(_)) => buf.push('g'),
+                    None => (),
                 }
             }
             if def.is_none() {
@@ -828,7 +858,7 @@ impl PerNs {
         match def {
             ModuleDefId::ModuleId(_) => PerNs::types(def, v, import),
             ModuleDefId::FunctionId(_) => {
-                PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+                PerNs::values(def, v, import.and_then(ImportOrExternCrate::import_or_glob))
             }
             ModuleDefId::AdtId(adt) => match adt {
                 AdtId::UnionId(_) => PerNs::types(def, v, import),
@@ -843,14 +873,14 @@ impl PerNs {
             },
             ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v, import),
             ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => {
-                PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+                PerNs::values(def, v, import.and_then(ImportOrExternCrate::import_or_glob))
             }
             ModuleDefId::TraitId(_) => PerNs::types(def, v, import),
             ModuleDefId::TraitAliasId(_) => PerNs::types(def, v, import),
             ModuleDefId::TypeAliasId(_) => PerNs::types(def, v, import),
             ModuleDefId::BuiltinType(_) => PerNs::types(def, v, import),
             ModuleDefId::MacroId(mac) => {
-                PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::into_import))
+                PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::import_or_glob))
             }
         }
     }
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 afdc49a2dc5..38733577d1c 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
@@ -372,6 +372,7 @@ language_item_table! {
     DerefMut,                sym::deref_mut,           deref_mut_trait,            Target::Trait,          GenericRequirement::Exact(0);
     DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy,        GenericRequirement::None;
     Receiver,                sym::receiver,            receiver_trait,             Target::Trait,          GenericRequirement::None;
+    ReceiverTarget,           sym::receiver_target,     receiver_target,            Target::AssocTy,        GenericRequirement::None;
 
     Fn,                      sym::fn_,                 fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
     FnMut,                   sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
@@ -410,6 +411,7 @@ language_item_table! {
     PanicLocation,           sym::panic_location,      panic_location,             Target::Struct,         GenericRequirement::None;
     PanicImpl,               sym::panic_impl,          panic_impl,                 Target::Fn,             GenericRequirement::None;
     PanicCannotUnwind,       sym::panic_cannot_unwind, panic_cannot_unwind,        Target::Fn,             GenericRequirement::Exact(0);
+    PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None;
     /// libstd panic entry point. Necessary for const eval to be able to catch it
     BeginPanic,              sym::begin_panic,         begin_panic_fn,             Target::Fn,             GenericRequirement::None;
 
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 84c105a0a34..c78818c642c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -114,6 +114,9 @@ pub struct ImportPathConfig {
     pub prefer_prelude: bool,
     /// If true, prefer abs path (starting with `::`) where it is available.
     pub prefer_absolute: bool,
+    /// If true, paths containing `#[unstable]` segments may be returned, but only if if there is no
+    /// stable path. This does not check, whether the item itself that is being imported is `#[unstable]`.
+    pub allow_unstable: bool,
 }
 
 #[derive(Debug)]
@@ -910,6 +913,7 @@ pub enum AssocItemId {
     ConstId(ConstId),
     TypeAliasId(TypeAliasId),
 }
+
 // FIXME: not every function, ... is actually an assoc item. maybe we should make
 // sure that you can only turn actual assoc items into AssocItemIds. This would
 // require not implementing From, and instead having some checked way of
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 1e4b42dff5f..06276335b71 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
@@ -28,7 +28,7 @@ use triomphe::Arc;
 use crate::{
     attr::Attrs,
     db::DefDatabase,
-    item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
+    item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
     item_tree::{
         self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
         ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
@@ -208,7 +208,7 @@ struct DefCollector<'a> {
     def_map: DefMap,
     // The dependencies of the current crate, including optional deps like `test`.
     deps: FxHashMap<Name, Dependency>,
-    glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, UseId)>>,
+    glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
     unresolved_imports: Vec<ImportDirective>,
     indeterminate_imports: Vec<(ImportDirective, PerNs)>,
     unresolved_macros: Vec<MacroDirective>,
@@ -524,11 +524,7 @@ impl DefCollector<'_> {
 
         match per_ns.types {
             Some(Item { def: ModuleDefId::ModuleId(m), import, .. }) => {
-                // FIXME: This should specifically look for a glob import somehow and record that here
-                self.def_map.prelude = Some((
-                    m,
-                    import.and_then(ImportOrExternCrate::into_import).map(|it| it.import),
-                ));
+                self.def_map.prelude = Some((m, import.and_then(ImportOrExternCrate::use_)));
             }
             types => {
                 tracing::debug!(
@@ -845,13 +841,14 @@ impl DefCollector<'_> {
                     def.values = None;
                     def.macros = None;
                 }
-                let imp = ImportType::Import(ImportId { import: id, idx: use_tree });
+                let imp = ImportOrExternCrate::Import(ImportId { use_: id, idx: use_tree });
                 tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 
                 self.update(module_id, &[(name.cloned(), def)], vis, Some(imp));
             }
-            ImportSource { kind: ImportKind::Glob, id, is_prelude, .. } => {
+            ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree } => {
                 tracing::debug!("glob import: {:?}", import);
+                let glob = GlobId { use_: id, idx: use_tree };
                 match def.take_types() {
                     Some(ModuleDefId::ModuleId(m)) => {
                         if is_prelude {
@@ -875,7 +872,12 @@ impl DefCollector<'_> {
                                 .filter(|(_, res)| !res.is_none())
                                 .collect::<Vec<_>>();
 
-                            self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
+                            self.update(
+                                module_id,
+                                &items,
+                                vis,
+                                Some(ImportOrExternCrate::Glob(glob)),
+                            );
                         } else {
                             // glob import from same crate => we do an initial
                             // import, and then need to propagate any further
@@ -907,11 +909,16 @@ impl DefCollector<'_> {
                                 .filter(|(_, res)| !res.is_none())
                                 .collect::<Vec<_>>();
 
-                            self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
+                            self.update(
+                                module_id,
+                                &items,
+                                vis,
+                                Some(ImportOrExternCrate::Glob(glob)),
+                            );
                             // record the glob import in case we add further items
-                            let glob = self.glob_imports.entry(m.local_id).or_default();
-                            match glob.iter_mut().find(|(mid, _, _)| *mid == module_id) {
-                                None => glob.push((module_id, vis, id)),
+                            let glob_imports = self.glob_imports.entry(m.local_id).or_default();
+                            match glob_imports.iter_mut().find(|(mid, _, _)| *mid == module_id) {
+                                None => glob_imports.push((module_id, vis, glob)),
                                 Some((_, old_vis, _)) => {
                                     if let Some(new_vis) = old_vis.max(vis, &self.def_map) {
                                         *old_vis = new_vis;
@@ -944,7 +951,12 @@ impl DefCollector<'_> {
                             (Some(name), res)
                         })
                         .collect::<Vec<_>>();
-                        self.update(module_id, &resolutions, vis, Some(ImportType::Glob(id)));
+                        self.update(
+                            module_id,
+                            &resolutions,
+                            vis,
+                            Some(ImportOrExternCrate::Glob(glob)),
+                        );
                     }
                     Some(d) => {
                         tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -964,7 +976,7 @@ impl DefCollector<'_> {
         resolutions: &[(Option<Name>, PerNs)],
         // Visibility this import will have
         vis: Visibility,
-        import: Option<ImportType>,
+        import: Option<ImportOrExternCrate>,
     ) {
         self.db.unwind_if_cancelled();
         self.update_recursive(module_id, resolutions, vis, import, 0)
@@ -978,7 +990,7 @@ impl DefCollector<'_> {
         // All resolutions are imported with this visibility; the visibilities in
         // the `PerNs` values are ignored and overwritten
         vis: Visibility,
-        import: Option<ImportType>,
+        import: Option<ImportOrExternCrate>,
         depth: usize,
     ) {
         if GLOB_RECURSION_LIMIT.check(depth).is_err() {
@@ -994,8 +1006,10 @@ impl DefCollector<'_> {
                         self.push_res_and_update_glob_vis(module_id, name, *res, vis, import);
                 }
                 None => {
-                    let tr = match res.take_types() {
-                        Some(ModuleDefId::TraitId(tr)) => tr,
+                    let (tr, import) = match res.take_types_full() {
+                        Some(Item { def: ModuleDefId::TraitId(tr), vis: _, import }) => {
+                            (tr, import)
+                        }
                         Some(other) => {
                             tracing::debug!("non-trait `_` import of {:?}", other);
                             continue;
@@ -1021,7 +1035,11 @@ impl DefCollector<'_> {
 
                     if should_update {
                         changed = true;
-                        self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
+                        self.def_map.modules[module_id].scope.push_unnamed_trait(
+                            tr,
+                            vis,
+                            import.and_then(ImportOrExternCrate::import),
+                        );
                     }
                 }
             }
@@ -1043,13 +1061,13 @@ impl DefCollector<'_> {
             .cloned()
             .collect::<Vec<_>>();
 
-        for (glob_importing_module, glob_import_vis, use_) in glob_imports {
+        for (glob_importing_module, glob_import_vis, glob) in glob_imports {
             let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis);
             self.update_recursive(
                 glob_importing_module,
                 resolutions,
                 vis,
-                Some(ImportType::Glob(use_)),
+                Some(ImportOrExternCrate::Glob(glob)),
                 depth + 1,
             );
         }
@@ -1061,7 +1079,7 @@ impl DefCollector<'_> {
         name: &Name,
         mut defs: PerNs,
         vis: Visibility,
-        def_import_type: Option<ImportType>,
+        def_import_type: Option<ImportOrExternCrate>,
     ) -> bool {
         // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
         // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
@@ -1074,10 +1092,10 @@ impl DefCollector<'_> {
                 let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
                     return false;
                 };
-                let Some(ImportType::Import(id)) = def_import_type else {
+                let Some(ImportOrExternCrate::Import(id)) = def_import_type else {
                     return false;
                 };
-                let use_id = id.import.lookup(self.db).id;
+                let use_id = id.use_.lookup(self.db).id;
                 let item_tree = use_id.item_tree(self.db);
                 let use_kind = item_tree[use_id.value].use_tree.kind();
                 let UseTreeKind::Single { path, .. } = use_kind else {
@@ -1100,7 +1118,7 @@ impl DefCollector<'_> {
 
         let mut changed = false;
 
-        if let Some(ImportType::Glob(_)) = def_import_type {
+        if let Some(ImportOrExternCrate::Glob(_)) = def_import_type {
             let prev_defs = self.def_map[module_id].scope.get(name);
 
             // Multiple globs may import the same item and they may override visibility from
@@ -1727,7 +1745,7 @@ impl ModCollector<'_, '_> {
                                 ),
                             )],
                             vis,
-                            Some(ImportType::ExternCrate(id)),
+                            Some(ImportOrExternCrate::ExternCrate(id)),
                         );
                     } else {
                         if let Some(name) = name {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
index ab4ffbb2c1e..d7e4ca41cd5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
@@ -4,7 +4,6 @@ use base_db::AnchoredPath;
 use hir_expand::{name::Name, HirFileIdExt};
 use limit::Limit;
 use span::EditionedFileId;
-use syntax::ToSmolStr as _;
 
 use crate::{db::DefDatabase, HirFileId};
 
@@ -35,7 +34,7 @@ impl ModDir {
         let path = match attr_path {
             None => {
                 let mut path = self.dir_path.clone();
-                path.push(&name.unescaped().display_no_db().to_smolstr());
+                path.push(name.as_str());
                 path
             }
             Some(attr_path) => {
@@ -66,7 +65,7 @@ impl ModDir {
         name: &Name,
         attr_path: Option<&str>,
     ) -> Result<(EditionedFileId, bool, ModDir), Box<[String]>> {
-        let name = name.unescaped();
+        let name = name.as_str();
 
         let mut candidate_files = ArrayVec::<_, 2>::new();
         match attr_path {
@@ -74,16 +73,8 @@ impl ModDir {
                 candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
             }
             None => {
-                candidate_files.push(format!(
-                    "{}{}.rs",
-                    self.dir_path.0,
-                    name.display(db.upcast())
-                ));
-                candidate_files.push(format!(
-                    "{}{}/mod.rs",
-                    self.dir_path.0,
-                    name.display(db.upcast())
-                ));
+                candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
+                candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
             }
         };
 
@@ -97,7 +88,7 @@ impl ModDir {
                 let dir_path = if root_dir_owner {
                     DirPath::empty()
                 } else {
-                    DirPath::new(format!("{}/", name.display(db.upcast())))
+                    DirPath::new(format!("{}/", name))
                 };
                 if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) {
                     return Ok((
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index 318aee04f7b..73fc6787bfe 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -103,8 +103,8 @@ mod a {
             c: t
 
             crate::a::b::c
-            A: v
-            b: t
+            A: vg
+            b: tg
         "#]],
     );
 }
@@ -256,8 +256,8 @@ pub enum Foo { Bar, Baz }
 "#,
         expect![[r#"
             crate
-            Bar: t v
-            Baz: t v
+            Bar: tg vg
+            Baz: tg vg
         "#]],
     );
 }
@@ -421,10 +421,10 @@ pub struct NotExported;
 "#,
         expect![[r#"
             crate
-            Exported: t v
-            PublicItem: t v
-            allowed_reexport: t
-            exported: t
+            Exported: tg vg
+            PublicItem: tg vg
+            allowed_reexport: tg
+            exported: tg
             not_allowed_reexport1: _
             not_allowed_reexport2: _
         "#]],
@@ -692,7 +692,7 @@ mod b {
             b: t
 
             crate::a
-            T: t v
+            T: t vg
 
             crate::b
             T: v
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
index 8963a576794..ddb9d4a134d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
@@ -18,9 +18,9 @@ pub struct Baz;
 "#,
         expect![[r#"
             crate
-            Baz: t v
-            Foo: t v
-            bar: t
+            Baz: tg vg
+            Foo: tg vg
+            bar: tg
             foo: t
 
             crate::foo
@@ -53,20 +53,20 @@ pub use super::*;
 "#,
         expect![[r#"
             crate
-            Baz: t v
-            Foo: t v
-            bar: t
+            Baz: tg vg
+            Foo: tg vg
+            bar: tg
             foo: t
 
             crate::foo
-            Baz: t v
+            Baz: tg vg
             Foo: t v
             bar: t
 
             crate::foo::bar
             Baz: t v
-            Foo: t v
-            bar: t
+            Foo: tg vg
+            bar: tg
         "#]],
     );
 }
@@ -91,20 +91,20 @@ pub use super::*;
 ",
         expect![[r#"
             crate
-            Baz: t v
-            bar: t
+            Baz: tg vg
+            bar: tg
             foo: t
 
             crate::foo
-            Baz: t v
+            Baz: tg vg
             PrivateStructFoo: t v
             bar: t
 
             crate::foo::bar
             Baz: t v
             PrivateStructBar: t v
-            PrivateStructFoo: t v
-            bar: t
+            PrivateStructFoo: tg vg
+            bar: tg
         "#]],
     );
 }
@@ -130,9 +130,9 @@ pub(crate) struct PubCrateStruct;
 ",
         expect![[r#"
             crate
-            Foo: t
-            PubCrateStruct: t v
-            bar: t
+            Foo: tg
+            PubCrateStruct: tg vg
+            bar: tg
             foo: t
 
             crate::foo
@@ -160,7 +160,7 @@ pub struct Baz;
 "#,
         expect![[r#"
             crate
-            Baz: t v
+            Baz: tg vg
         "#]],
     );
 }
@@ -178,7 +178,7 @@ struct Foo;
 "#,
         expect![[r#"
             crate
-            Baz: t v
+            Baz: tg vg
         "#]],
     );
 }
@@ -193,8 +193,8 @@ use self::Foo::*;
 "#,
         expect![[r#"
             crate
-            Bar: t v
-            Baz: t v
+            Bar: tg vg
+            Baz: tg vg
             Foo: t
         "#]],
     );
@@ -210,8 +210,8 @@ use self::Foo::{*};
 "#,
         expect![[r#"
             crate
-            Bar: t v
-            Baz: t v
+            Bar: tg vg
+            Baz: tg vg
             Foo: t
         "#]],
     );
@@ -359,7 +359,7 @@ use event::Event;
             event: t
 
             crate::event
-            Event: t v
+            Event: t vg
             serenity: t
 
             crate::event::serenity
@@ -388,10 +388,10 @@ use reexport::*;
 "#,
         expect![[r#"
             crate
-            Trait: t
+            Trait: tg
             defs: t
-            function: v
-            makro: m
+            function: vg
+            makro: mg
             reexport: t
 
             crate::defs
@@ -400,10 +400,10 @@ use reexport::*;
             makro: m
 
             crate::reexport
-            Trait: t
-            function: v
+            Trait: tg
+            function: vg
             inner: t
-            makro: m
+            makro: mg
 
             crate::reexport::inner
             Trait: ti
@@ -442,12 +442,12 @@ mod glob_target {
             ShouldBePrivate: t v
 
             crate::outer
-            ShouldBePrivate: t v
+            ShouldBePrivate: tg vg
             inner_superglob: t
 
             crate::outer::inner_superglob
-            ShouldBePrivate: t v
-            inner_superglob: t
+            ShouldBePrivate: tg vg
+            inner_superglob: tg
         "#]],
     );
 }
@@ -473,20 +473,20 @@ use reexport_2::*;
 "#,
         expect![[r#"
             crate
-            Placeholder: t v
+            Placeholder: tg vg
             libs: t
-            reexport_1: t
+            reexport_1: tg
             reexport_2: t
 
             crate::libs
             Placeholder: t v
 
             crate::reexport_2
-            Placeholder: t v
+            Placeholder: tg vg
             reexport_1: t
 
             crate::reexport_2::reexport_1
-            Placeholder: t v
+            Placeholder: tg vg
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index a05c4dcf9bd..610886d55f4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -97,9 +97,9 @@ macro_rules! structs {
             bar: t
 
             crate::bar
-            Bar: t
-            Foo: t
-            bar: t
+            Bar: tg
+            Foo: tg
+            bar: tg
         "#]],
     );
 }
@@ -130,9 +130,9 @@ macro_rules! structs {
             bar: t
 
             crate::bar
-            Bar: t
-            Foo: t
-            bar: t
+            Bar: tg
+            Foo: tg
+            bar: tg
         "#]],
     );
 }
@@ -169,9 +169,9 @@ macro_rules! inner {
             bar: t
 
             crate::bar
-            Bar: t
-            Foo: t
-            bar: t
+            Bar: tg
+            Foo: tg
+            bar: tg
         "#]],
     );
 }
@@ -794,7 +794,7 @@ pub trait Clone {}
 "#,
         expect![[r#"
             crate
-            Clone: t m
+            Clone: tg mg
         "#]],
     );
 }
@@ -1075,9 +1075,9 @@ macro_rules! mbe {
 "#,
         expect![[r#"
             crate
-            DummyTrait: m
-            attribute_macro: m
-            function_like_macro: m
+            DummyTrait: mg
+            attribute_macro: mg
+            function_like_macro: mg
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
index 899dd4afffe..c2d3f67f17e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
@@ -6,7 +6,7 @@
 use bitflags::bitflags;
 
 use crate::{
-    item_scope::{ImportId, ImportOrExternCrate, ItemInNs},
+    item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob, ItemInNs},
     visibility::Visibility,
     MacroId, ModuleDefId,
 };
@@ -36,8 +36,8 @@ pub struct Item<Def, Import = ImportId> {
 }
 
 pub type TypesItem = Item<ModuleDefId, ImportOrExternCrate>;
-pub type ValuesItem = Item<ModuleDefId>;
-pub type MacrosItem = Item<MacroId>;
+pub type ValuesItem = Item<ModuleDefId, ImportOrGlob>;
+pub type MacrosItem = Item<MacroId, ImportOrGlob>;
 
 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
 pub struct PerNs {
@@ -59,7 +59,7 @@ impl PerNs {
         PerNs { types: None, values: None, macros: None }
     }
 
-    pub fn values(def: ModuleDefId, vis: Visibility, import: Option<ImportId>) -> PerNs {
+    pub fn values(def: ModuleDefId, vis: Visibility, import: Option<ImportOrGlob>) -> PerNs {
         PerNs { types: None, values: Some(Item { def, vis, import }), macros: None }
     }
 
@@ -78,13 +78,13 @@ impl PerNs {
             values: Some(Item {
                 def: values,
                 vis,
-                import: import.and_then(ImportOrExternCrate::into_import),
+                import: import.and_then(ImportOrExternCrate::import_or_glob),
             }),
             macros: None,
         }
     }
 
-    pub fn macros(def: MacroId, vis: Visibility, import: Option<ImportId>) -> PerNs {
+    pub fn macros(def: MacroId, vis: Visibility, import: Option<ImportOrGlob>) -> PerNs {
         PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) }
     }
 
@@ -108,7 +108,7 @@ impl PerNs {
         self.values.map(|it| it.def)
     }
 
-    pub fn take_values_import(self) -> Option<(ModuleDefId, Option<ImportId>)> {
+    pub fn take_values_import(self) -> Option<(ModuleDefId, Option<ImportOrGlob>)> {
         self.values.map(|it| (it.def, it.import))
     }
 
@@ -116,7 +116,7 @@ impl PerNs {
         self.macros.map(|it| it.def)
     }
 
-    pub fn take_macros_import(self) -> Option<(MacroId, Option<ImportId>)> {
+    pub fn take_macros_import(self) -> Option<(MacroId, Option<ImportOrGlob>)> {
         self.macros.map(|it| (it.def, it.import))
     }
 
@@ -159,14 +159,12 @@ impl PerNs {
             .map(|it| (ItemInNs::Types(it.def), it.import))
             .into_iter()
             .chain(
-                self.values.map(|it| {
-                    (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::Import))
-                }),
+                self.values
+                    .map(|it| (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::from))),
             )
             .chain(
-                self.macros.map(|it| {
-                    (ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::Import))
-                }),
+                self.macros
+                    .map(|it| (ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::from))),
             )
     }
 }
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 0b9b6da8d51..8c556d8a8c3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -19,7 +19,7 @@ use crate::{
     db::DefDatabase,
     generics::{GenericParams, TypeOrConstParamData},
     hir::{BindingId, ExprId, LabelId},
-    item_scope::{BuiltinShadowMode, ImportId, ImportOrExternCrate, BUILTIN_SCOPE},
+    item_scope::{BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, BUILTIN_SCOPE},
     lang_item::LangItemTarget,
     nameres::{DefMap, MacroSubNs, ResolvePathResultPrefixInfo},
     path::{ModPath, Path, PathKind},
@@ -107,7 +107,7 @@ pub enum TypeNs {
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum ResolveValueResult {
-    ValueNs(ValueNs, Option<ImportId>),
+    ValueNs(ValueNs, Option<ImportOrGlob>),
     Partial(TypeNs, usize, Option<ImportOrExternCrate>),
 }
 
@@ -485,7 +485,7 @@ impl Resolver {
         db: &dyn DefDatabase,
         path: &ModPath,
         expected_macro_kind: Option<MacroSubNs>,
-    ) -> Option<(MacroId, Option<ImportId>)> {
+    ) -> Option<(MacroId, Option<ImportOrGlob>)> {
         let (item_map, module) = self.item_scope();
         item_map
             .resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind)
@@ -1014,7 +1014,7 @@ impl ModuleItemMap {
     }
 }
 
-fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportId>)> {
+fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportOrGlob>)> {
     let (def, import) = per_ns.take_values_import()?;
     let res = match def {
         ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
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 89eae862bd9..f0cf7ebf479 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
@@ -23,15 +23,6 @@ pub struct ModPath {
     segments: SmallVec<[Name; 1]>,
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct UnescapedModPath<'a>(&'a ModPath);
-
-impl<'a> UnescapedModPath<'a> {
-    pub fn display(&'a self, db: &'a dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
-        UnescapedDisplay { db, path: self }
-    }
-}
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum PathKind {
     Plain,
@@ -135,9 +126,11 @@ impl ModPath {
             _ => None,
         }
     }
-
-    pub fn unescaped(&self) -> UnescapedModPath<'_> {
-        UnescapedModPath(self)
+    pub fn display_verbatim<'a>(
+        &'a self,
+        db: &'a dyn crate::db::ExpandDatabase,
+    ) -> impl fmt::Display + 'a {
+        Display { db, path: self, edition: None }
     }
 
     pub fn display<'a>(
@@ -145,7 +138,7 @@ impl ModPath {
         db: &'a dyn crate::db::ExpandDatabase,
         edition: Edition,
     ) -> impl fmt::Display + 'a {
-        Display { db, path: self, edition }
+        Display { db, path: self, edition: Some(edition) }
     }
 }
 
@@ -158,23 +151,12 @@ impl Extend<Name> for ModPath {
 struct Display<'a> {
     db: &'a dyn ExpandDatabase,
     path: &'a ModPath,
-    edition: Edition,
+    edition: Option<Edition>,
 }
 
 impl fmt::Display for Display<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        display_fmt_path(self.db, self.path, f, Escape::IfNeeded(self.edition))
-    }
-}
-
-struct UnescapedDisplay<'a> {
-    db: &'a dyn ExpandDatabase,
-    path: &'a UnescapedModPath<'a>,
-}
-
-impl fmt::Display for UnescapedDisplay<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        display_fmt_path(self.db, self.path.0, f, Escape::No)
+        display_fmt_path(self.db, self.path, f, self.edition)
     }
 }
 
@@ -184,16 +166,11 @@ impl From<Name> for ModPath {
     }
 }
 
-enum Escape {
-    No,
-    IfNeeded(Edition),
-}
-
 fn display_fmt_path(
     db: &dyn ExpandDatabase,
     path: &ModPath,
     f: &mut fmt::Formatter<'_>,
-    escaped: Escape,
+    edition: Option<Edition>,
 ) -> fmt::Result {
     let mut first_segment = true;
     let mut add_segment = |s| -> fmt::Result {
@@ -221,10 +198,10 @@ fn display_fmt_path(
             f.write_str("::")?;
         }
         first_segment = false;
-        match escaped {
-            Escape::IfNeeded(edition) => segment.display(db, edition).fmt(f)?,
-            Escape::No => segment.unescaped().display(db).fmt(f)?,
-        }
+        match edition {
+            Some(edition) => segment.display(db, edition).fmt(f)?,
+            None => fmt::Display::fmt(segment.as_str(), f)?,
+        };
     }
     Ok(())
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index cc53d2e34aa..848870c3a38 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -4,8 +4,8 @@ use std::fmt;
 
 use intern::{sym, Symbol};
 use span::{Edition, SyntaxContextId};
-use syntax::ast;
 use syntax::utils::is_raw_identifier;
+use syntax::{ast, format_smolstr};
 
 /// `Name` is a wrapper around string, which is used in hir for both references
 /// and declarations. In theory, names should also carry hygiene info, but we are
@@ -51,33 +51,26 @@ impl PartialEq<Symbol> for Name {
     }
 }
 
+impl PartialEq<&Symbol> for Name {
+    fn eq(&self, &sym: &&Symbol) -> bool {
+        self.symbol == *sym
+    }
+}
+
 impl PartialEq<Name> for Symbol {
     fn eq(&self, name: &Name) -> bool {
         *self == name.symbol
     }
 }
 
-/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct UnescapedName<'a>(&'a Name);
-
-impl<'a> UnescapedName<'a> {
-    pub fn display(self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
-        _ = db;
-        UnescapedDisplay { name: self }
-    }
-    #[doc(hidden)]
-    pub fn display_no_db(self) -> impl fmt::Display + 'a {
-        UnescapedDisplay { name: self }
+impl PartialEq<Name> for &Symbol {
+    fn eq(&self, name: &Name) -> bool {
+        **self == name.symbol
     }
 }
 
 impl Name {
-    /// Note: this is private to make creating name from random string hard.
-    /// Hopefully, this should allow us to integrate hygiene cleaner in the
-    /// future, and to switch to interned representation of names.
     fn new_text(text: &str) -> Name {
-        debug_assert!(!text.starts_with("r#"));
         Name { symbol: Symbol::intern(text), ctx: () }
     }
 
@@ -87,12 +80,15 @@ impl Name {
         // Can't do that for all `SyntaxContextId`s because it breaks Salsa.
         ctx.remove_root_edition();
         _ = ctx;
-        Self::new_text(text)
+        match text.strip_prefix("r#") {
+            Some(text) => Self::new_text(text),
+            None => Self::new_text(text),
+        }
     }
 
     pub fn new_root(text: &str) -> Name {
         // The edition doesn't matter for hygiene.
-        Self::new(text.trim_start_matches("r#"), SyntaxContextId::root(Edition::Edition2015))
+        Self::new(text, SyntaxContextId::root(Edition::Edition2015))
     }
 
     pub fn new_tuple_field(idx: usize) -> Name {
@@ -119,12 +115,22 @@ impl Name {
     }
 
     pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
-        Self::new_text(lt.text().as_str().trim_start_matches("r#"))
+        let text = lt.text();
+        match text.strip_prefix("'r#") {
+            Some(text) => Self::new_text(&format_smolstr!("'{text}")),
+            None => Self::new_text(text.as_str()),
+        }
+    }
+
+    pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
+        debug_assert!(!symbol.as_str().starts_with("r#"));
+        _ = ctx;
+        Self { symbol, ctx: () }
     }
 
-    /// Resolve a name from the text of token.
-    fn resolve(raw_text: &str) -> Name {
-        Name::new_text(raw_text.trim_start_matches("r#"))
+    // FIXME: This needs to go once we have hygiene
+    pub fn new_symbol_root(sym: Symbol) -> Self {
+        Self::new_symbol(sym, SyntaxContextId::root(Edition::Edition2015))
     }
 
     /// A fake name for things missing in the source code.
@@ -161,22 +167,19 @@ impl Name {
         self.symbol.as_str().parse().ok()
     }
 
+    /// Whether this name needs to be escaped in the given edition via `r#`.
+    pub fn needs_escape(&self, edition: Edition) -> bool {
+        is_raw_identifier(self.symbol.as_str(), edition)
+    }
+
     /// Returns the text this name represents if it isn't a tuple field.
     ///
     /// Do not use this for user-facing text, use `display` instead to handle editions properly.
+    // FIXME: This should take a database argument to hide the interning
     pub fn as_str(&self) -> &str {
         self.symbol.as_str()
     }
 
-    // FIXME: Remove this
-    pub fn unescaped(&self) -> UnescapedName<'_> {
-        UnescapedName(self)
-    }
-
-    pub fn needs_escape(&self, edition: Edition) -> bool {
-        is_raw_identifier(self.symbol.as_str(), edition)
-    }
-
     pub fn display<'a>(
         &'a self,
         db: &dyn crate::db::ExpandDatabase,
@@ -186,7 +189,7 @@ impl Name {
         self.display_no_db(edition)
     }
 
-    // FIXME: Remove this
+    // FIXME: Remove this in favor of `display`, see fixme on `as_str`
     #[doc(hidden)]
     pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ {
         Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) }
@@ -195,24 +198,6 @@ impl Name {
     pub fn symbol(&self) -> &Symbol {
         &self.symbol
     }
-
-    pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
-        debug_assert!(!symbol.as_str().starts_with("r#"));
-        _ = ctx;
-        Self { symbol, ctx: () }
-    }
-
-    // FIXME: This needs to go once we have hygiene
-    pub fn new_symbol_root(sym: Symbol) -> Self {
-        debug_assert!(!sym.as_str().starts_with("r#"));
-        Self { symbol: sym, ctx: () }
-    }
-
-    // FIXME: Remove this
-    #[inline]
-    pub fn eq_ident(&self, ident: &str) -> bool {
-        self.as_str() == ident.trim_start_matches("r#")
-    }
 }
 
 struct Display<'a> {
@@ -229,17 +214,6 @@ impl fmt::Display for Display<'_> {
     }
 }
 
-struct UnescapedDisplay<'a> {
-    name: UnescapedName<'a>,
-}
-
-impl fmt::Display for UnescapedDisplay<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let symbol = self.name.0.symbol.as_str();
-        fmt::Display::fmt(symbol, f)
-    }
-}
-
 pub trait AsName {
     fn as_name(&self) -> Name;
 }
@@ -248,14 +222,14 @@ impl AsName for ast::NameRef {
     fn as_name(&self) -> Name {
         match self.as_tuple_field() {
             Some(idx) => Name::new_tuple_field(idx),
-            None => Name::resolve(&self.text()),
+            None => Name::new_root(&self.text()),
         }
     }
 }
 
 impl AsName for ast::Name {
     fn as_name(&self) -> Name {
-        Name::resolve(&self.text())
+        Name::new_root(&self.text())
     }
 }
 
@@ -270,7 +244,7 @@ impl AsName for ast::NameOrNameRef {
 
 impl<Span> AsName for tt::Ident<Span> {
     fn as_name(&self) -> Name {
-        Name::resolve(self.sym.as_str())
+        Name::new_root(self.sym.as_str())
     }
 }
 
@@ -288,6 +262,6 @@ impl AsName for ast::FieldKind {
 
 impl AsName for base_db::Dependency {
     fn as_name(&self) -> Name {
-        Name::new_text(&self.name)
+        Name::new_root(&self.name)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index 2b5342314a6..62feca5f8cb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -17,7 +17,7 @@ use crate::{
     TraitEnvironment, Ty, TyBuilder, TyKind,
 };
 
-static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
+static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(20);
 
 #[derive(Debug)]
 pub(crate) enum AutoderefKind {
@@ -39,7 +39,7 @@ pub fn autoderef(
 ) -> impl Iterator<Item = Ty> {
     let mut table = InferenceTable::new(db, env);
     let ty = table.instantiate_canonical(ty);
-    let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false);
+    let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false, false);
     let mut v = Vec::new();
     while let Some((ty, _steps)) = autoderef.next() {
         // `ty` may contain unresolved inference variables. Since there's no chance they would be
@@ -49,7 +49,7 @@ pub fn autoderef(
         // If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we
         // would revisit some already visited types. Stop here to avoid duplication.
         //
-        // XXX: The recursion limit for `Autoderef` is currently 10, so `Vec::contains()` shouldn't
+        // XXX: The recursion limit for `Autoderef` is currently 20, so `Vec::contains()` shouldn't
         // be too expensive. Replace this duplicate check with `FxHashSet` if it proves to be more
         // performant.
         if v.contains(&resolved) {
@@ -89,12 +89,18 @@ pub(crate) struct Autoderef<'table, 'db, T = Vec<(AutoderefKind, Ty)>> {
     at_start: bool,
     steps: T,
     explicit: bool,
+    use_receiver_trait: bool,
 }
 
 impl<'table, 'db> Autoderef<'table, 'db> {
-    pub(crate) fn new(table: &'table mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
+    pub(crate) fn new(
+        table: &'table mut InferenceTable<'db>,
+        ty: Ty,
+        explicit: bool,
+        use_receiver_trait: bool,
+    ) -> Self {
         let ty = table.resolve_ty_shallow(&ty);
-        Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
+        Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit, use_receiver_trait }
     }
 
     pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
@@ -107,9 +113,10 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> {
         table: &'table mut InferenceTable<'db>,
         ty: Ty,
         explicit: bool,
+        use_receiver_trait: bool,
     ) -> Self {
         let ty = table.resolve_ty_shallow(&ty);
-        Autoderef { table, ty, at_start: true, steps: 0, explicit }
+        Autoderef { table, ty, at_start: true, steps: 0, explicit, use_receiver_trait }
     }
 }
 
@@ -137,7 +144,8 @@ impl<T: TrackAutoderefSteps> Iterator for Autoderef<'_, '_, T> {
             return None;
         }
 
-        let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;
+        let (kind, new_ty) =
+            autoderef_step(self.table, self.ty.clone(), self.explicit, self.use_receiver_trait)?;
 
         self.steps.push(kind, &self.ty);
         self.ty = new_ty;
@@ -150,11 +158,12 @@ pub(crate) fn autoderef_step(
     table: &mut InferenceTable<'_>,
     ty: Ty,
     explicit: bool,
+    use_receiver_trait: bool,
 ) -> Option<(AutoderefKind, Ty)> {
     if let Some(derefed) = builtin_deref(table.db, &ty, explicit) {
         Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
     } else {
-        Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
+        Some((AutoderefKind::Overloaded, deref_by_trait(table, ty, use_receiver_trait)?))
     }
 }
 
@@ -176,6 +185,7 @@ pub(crate) fn builtin_deref<'ty>(
 pub(crate) fn deref_by_trait(
     table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>,
     ty: Ty,
+    use_receiver_trait: bool,
 ) -> Option<Ty> {
     let _p = tracing::info_span!("deref_by_trait").entered();
     if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
@@ -183,14 +193,25 @@ pub(crate) fn deref_by_trait(
         return None;
     }
 
-    let deref_trait =
-        db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?;
+    let trait_id = || {
+        if use_receiver_trait {
+            if let Some(receiver) =
+                db.lang_item(table.trait_env.krate, LangItem::Receiver).and_then(|l| l.as_trait())
+            {
+                return Some(receiver);
+            }
+        }
+        // Old rustc versions might not have `Receiver` trait.
+        // Fallback to `Deref` if they don't
+        db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())
+    };
+    let trait_id = trait_id()?;
     let target = db
-        .trait_data(deref_trait)
+        .trait_data(trait_id)
         .associated_type_by_name(&Name::new_symbol_root(sym::Target.clone()))?;
 
     let projection = {
-        let b = TyBuilder::subst_for_def(db, deref_trait, None);
+        let b = TyBuilder::subst_for_def(db, trait_id, None);
         if b.remaining() != 1 {
             // the Target type + Deref trait should only have one generic parameter,
             // namely Deref's Self type
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index 4991d173b9c..774991560e9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -231,8 +231,7 @@ impl<'a> DeclValidator<'a> {
             .filter_map(|(pat_id, pat)| match pat {
                 Pat::Bind { id, .. } => {
                     let bind_name = &body.bindings[*id].name;
-                    let mut suggested_text =
-                        to_lower_snake_case(&bind_name.unescaped().display_no_db().to_smolstr())?;
+                    let mut suggested_text = to_lower_snake_case(bind_name.as_str())?;
                     if is_raw_identifier(&suggested_text, edition) {
                         suggested_text.insert_str(0, "r#");
                     }
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 3545bf76776..ae8fbe2ce6d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -34,6 +34,7 @@ use rustc_apfloat::{
     ieee::{Half as f16, Quad as f128},
     Float,
 };
+use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use span::Edition;
 use stdx::never;
@@ -87,6 +88,35 @@ pub struct HirFormatter<'a> {
     omit_verbose_types: bool,
     closure_style: ClosureStyle,
     display_target: DisplayTarget,
+    bounds_formatting_ctx: BoundsFormattingCtx,
+}
+
+#[derive(Default)]
+enum BoundsFormattingCtx {
+    Entered {
+        /// We can have recursive bounds like the following case:
+        /// ```rust
+        /// where
+        ///     T: Foo,
+        ///     T::FooAssoc: Baz<<T::FooAssoc as Bar>::BarAssoc> + Bar
+        /// ```
+        /// So, record the projection types met while formatting bounds and
+        //. prevent recursing into their bounds to avoid infinite loops.
+        projection_tys_met: FxHashSet<ProjectionTy>,
+    },
+    #[default]
+    Exited,
+}
+
+impl BoundsFormattingCtx {
+    fn contains(&mut self, proj: &ProjectionTy) -> bool {
+        match self {
+            BoundsFormattingCtx::Entered { projection_tys_met } => {
+                projection_tys_met.contains(proj)
+            }
+            BoundsFormattingCtx::Exited => false,
+        }
+    }
 }
 
 impl HirFormatter<'_> {
@@ -97,6 +127,30 @@ impl HirFormatter<'_> {
     fn end_location_link(&mut self) {
         self.fmt.end_location_link();
     }
+
+    fn format_bounds_with<T, F: FnOnce(&mut Self) -> T>(
+        &mut self,
+        target: ProjectionTy,
+        format_bounds: F,
+    ) -> T {
+        match self.bounds_formatting_ctx {
+            BoundsFormattingCtx::Entered { ref mut projection_tys_met } => {
+                projection_tys_met.insert(target);
+                format_bounds(self)
+            }
+            BoundsFormattingCtx::Exited => {
+                let mut projection_tys_met = FxHashSet::default();
+                projection_tys_met.insert(target);
+                self.bounds_formatting_ctx = BoundsFormattingCtx::Entered { projection_tys_met };
+                let res = format_bounds(self);
+                // Since we want to prevent only the infinite recursions in bounds formatting
+                // and do not want to skip formatting of other separate bounds, clear context
+                // when exiting the formatting of outermost bounds
+                self.bounds_formatting_ctx = BoundsFormattingCtx::Exited;
+                res
+            }
+        }
+    }
 }
 
 pub trait HirDisplay {
@@ -220,6 +274,7 @@ pub trait HirDisplay {
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
             show_container_bounds: false,
+            bounds_formatting_ctx: Default::default(),
         }) {
             Ok(()) => {}
             Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
@@ -427,6 +482,7 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
             display_target: self.display_target,
             closure_style: self.closure_style,
             show_container_bounds: self.show_container_bounds,
+            bounds_formatting_ctx: Default::default(),
         })
     }
 
@@ -479,42 +535,46 @@ impl HirDisplay for ProjectionTy {
         // `<Param as Trait>::Assoc`
         if !f.display_target.is_source_code() {
             if let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
-                let db = f.db;
-                let id = from_placeholder_idx(db, *idx);
-                let generics = generics(db.upcast(), id.parent);
-
-                let substs = generics.placeholder_subst(db);
-                let bounds = db
-                    .generic_predicates(id.parent)
-                    .iter()
-                    .map(|pred| pred.clone().substitute(Interner, &substs))
-                    .filter(|wc| match wc.skip_binders() {
-                        WhereClause::Implemented(tr) => {
-                            match tr.self_type_parameter(Interner).kind(Interner) {
-                                TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
-                                _ => false,
+                if !f.bounds_formatting_ctx.contains(self) {
+                    let db = f.db;
+                    let id = from_placeholder_idx(db, *idx);
+                    let generics = generics(db.upcast(), id.parent);
+
+                    let substs = generics.placeholder_subst(db);
+                    let bounds = db
+                        .generic_predicates(id.parent)
+                        .iter()
+                        .map(|pred| pred.clone().substitute(Interner, &substs))
+                        .filter(|wc| match wc.skip_binders() {
+                            WhereClause::Implemented(tr) => {
+                                matches!(
+                                    tr.self_type_parameter(Interner).kind(Interner),
+                                    TyKind::Alias(_)
+                                )
                             }
-                        }
-                        WhereClause::TypeOutlives(t) => match t.ty.kind(Interner) {
-                            TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
-                            _ => false,
-                        },
-                        // We shouldn't be here if these exist
-                        WhereClause::AliasEq(_) => false,
-                        WhereClause::LifetimeOutlives(_) => false,
-                    })
-                    .collect::<Vec<_>>();
-                if !bounds.is_empty() {
-                    return write_bounds_like_dyn_trait_with_prefix(
-                        f,
-                        "impl",
-                        Either::Left(
-                            &TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner),
-                        ),
-                        &bounds,
-                        SizedByDefault::NotSized,
-                    );
-                };
+                            WhereClause::TypeOutlives(t) => {
+                                matches!(t.ty.kind(Interner), TyKind::Alias(_))
+                            }
+                            // We shouldn't be here if these exist
+                            WhereClause::AliasEq(_) => false,
+                            WhereClause::LifetimeOutlives(_) => false,
+                        })
+                        .collect::<Vec<_>>();
+                    if !bounds.is_empty() {
+                        return f.format_bounds_with(self.clone(), |f| {
+                            write_bounds_like_dyn_trait_with_prefix(
+                                f,
+                                "impl",
+                                Either::Left(
+                                    &TyKind::Alias(AliasTy::Projection(self.clone()))
+                                        .intern(Interner),
+                                ),
+                                &bounds,
+                                SizedByDefault::NotSized,
+                            )
+                        });
+                    }
+                }
             }
         }
 
@@ -1159,6 +1219,7 @@ impl HirDisplay for Ty {
                                 prefer_no_std: false,
                                 prefer_prelude: true,
                                 prefer_absolute: false,
+                                allow_unstable: true,
                             },
                         ) {
                             write!(f, "{}", path.display(f.db.upcast(), f.edition()))?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 2523aba5383..9283c46d0f6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -277,7 +277,7 @@ impl CapturedItem {
     /// Converts the place to a name that can be inserted into source code.
     pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String {
         let body = db.body(owner);
-        let mut result = body[self.place.local].name.unescaped().display(db.upcast()).to_string();
+        let mut result = body[self.place.local].name.as_str().to_owned();
         for proj in &self.place.projections {
             match proj {
                 ProjectionElem::Deref => {}
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 2fe90a8a924..d40816ba8ce 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
@@ -420,7 +420,7 @@ impl InferenceTable<'_> {
 
         let snapshot = self.snapshot();
 
-        let mut autoderef = Autoderef::new(self, from_ty.clone(), false);
+        let mut autoderef = Autoderef::new(self, from_ty.clone(), false, false);
         let mut first_error = None;
         let mut found = None;
 
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 6b6c0348dcb..b951443897c 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
@@ -487,7 +487,7 @@ impl InferenceContext<'_> {
             }
             Expr::Call { callee, args, .. } => {
                 let callee_ty = self.infer_expr(*callee, &Expectation::none(), ExprIsRead::Yes);
-                let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false);
+                let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false, true);
                 let (res, derefed_callee) = loop {
                     let Some((callee_deref_ty, _)) = derefs.next() else {
                         break (None, callee_ty.clone());
@@ -854,7 +854,7 @@ impl InferenceContext<'_> {
                         if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) {
                             self.resolve_ty_shallow(derefed)
                         } else {
-                            deref_by_trait(&mut self.table, inner_ty)
+                            deref_by_trait(&mut self.table, inner_ty, false)
                                 .unwrap_or_else(|| self.err_ty())
                         }
                     }
@@ -1718,7 +1718,7 @@ impl InferenceContext<'_> {
         receiver_ty: &Ty,
         name: &Name,
     ) -> Option<(Ty, Either<FieldId, TupleFieldId>, Vec<Adjustment>, bool)> {
-        let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false);
+        let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false, false);
         let mut private_field = None;
         let res = autoderef.by_ref().find_map(|(derefed_ty, _)| {
             let (field_id, parameters) = match derefed_ty.kind(Interner) {
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 182032f0481..1cea67ee964 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
@@ -528,7 +528,7 @@ impl ReceiverAdjustments {
         let mut ty = table.resolve_ty_shallow(&ty);
         let mut adjust = Vec::new();
         for _ in 0..self.autoderefs {
-            match autoderef::autoderef_step(table, ty.clone(), true) {
+            match autoderef::autoderef_step(table, ty.clone(), true, false) {
                 None => {
                     never!("autoderef not possible for {:?}", ty);
                     ty = TyKind::Error.intern(Interner);
@@ -1106,7 +1106,8 @@ fn iterate_method_candidates_by_receiver(
     // be found in any of the derefs of receiver_ty, so we have to go through
     // that, including raw derefs.
     table.run_in_snapshot(|table| {
-        let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
+        let mut autoderef =
+            autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
         while let Some((self_ty, _)) = autoderef.next() {
             iterate_inherent_methods(
                 &self_ty,
@@ -1123,7 +1124,8 @@ fn iterate_method_candidates_by_receiver(
         ControlFlow::Continue(())
     })?;
     table.run_in_snapshot(|table| {
-        let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
+        let mut autoderef =
+            autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
         while let Some((self_ty, _)) = autoderef.next() {
             if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) {
                 // don't try to resolve methods on unknown types
@@ -1709,7 +1711,7 @@ fn autoderef_method_receiver(
     ty: Ty,
 ) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
     let mut deref_chain: Vec<_> = Vec::new();
-    let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false);
+    let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false, true);
     while let Some((ty, derefs)) = autoderef.next() {
         deref_chain.push((
             autoderef.table.canonicalize(ty),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index 74acf23b75a..8866de22dfb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -1343,7 +1343,7 @@ fn foo<T: Trait>(a: &T) {
 fn autoderef_visibility_field() {
     check(
         r#"
-//- minicore: deref
+//- minicore: receiver
 mod a {
     pub struct Foo(pub char);
     pub struct Bar(i32);
@@ -1375,7 +1375,7 @@ fn autoderef_visibility_method() {
     cov_mark::check!(autoderef_candidate_not_visible);
     check(
         r#"
-//- minicore: deref
+//- minicore: receiver
 mod a {
     pub struct Foo(pub char);
     impl Foo {
@@ -1741,7 +1741,7 @@ fn main() {
 fn deref_fun_1() {
     check_types(
         r#"
-//- minicore: deref
+//- minicore: receiver
 
 struct A<T, U>(T, U);
 struct B<T>(T);
@@ -1782,7 +1782,7 @@ fn test() {
 fn deref_fun_2() {
     check_types(
         r#"
-//- minicore: deref
+//- minicore: receiver
 
 struct A<T, U>(T, U);
 struct B<T>(T);
@@ -1903,7 +1903,7 @@ pub fn test(generic_args: impl Into<Foo>) {
 fn bad_inferred_reference_2() {
     check_no_mismatches(
         r#"
-//- minicore: deref
+//- minicore: receiver
 trait ExactSizeIterator {
     fn len(&self) -> usize;
 }
@@ -2054,7 +2054,7 @@ fn foo() {
 fn box_deref_is_builtin() {
     check(
         r#"
-//- minicore: deref
+//- minicore: receiver
 use core::ops::Deref;
 
 #[lang = "owned_box"]
@@ -2087,7 +2087,7 @@ fn test() {
 fn manually_drop_deref_is_not_builtin() {
     check(
         r#"
-//- minicore: manually_drop, deref
+//- minicore: manually_drop, receiver
 struct Foo;
 impl Foo {
     fn foo(&self) {}
@@ -2105,7 +2105,7 @@ fn test() {
 fn mismatched_args_due_to_supertraits_with_deref() {
     check_no_mismatches(
         r#"
-//- minicore: deref
+//- minicore: receiver
 use core::ops::Deref;
 
 trait Trait1 {
@@ -2139,3 +2139,34 @@ fn problem_method<T: Trait3>() {
 "#,
     );
 }
+
+#[test]
+fn receiver_without_deref_impl() {
+    check(
+        r#"
+//- minicore: receiver
+use core::ops::Receiver;
+
+struct Foo;
+
+impl Foo {
+    fn foo1(self: &Bar) -> i32 { 42 }
+    fn foo2(self: Bar) -> bool { true }
+}
+
+struct Bar;
+
+impl Receiver for Bar {
+    type Target = Foo;
+}
+
+fn main() {
+    let bar = Bar;
+    let _v1 = bar.foo1();
+      //^^^ type: i32
+    let _v2 = bar.foo2();
+      //^^^ type: bool
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index db3121d3cd3..0cbc75726bf 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -45,7 +45,7 @@ use hir_def::{
     body::BodyDiagnostic,
     data::{adt::VariantData, TraitFlags},
     generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
-    hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat},
+    hir::{BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat},
     item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode},
     lang_item::LangItemTarget,
     layout::{self, ReprOptions, TargetDataLayout},
@@ -2470,20 +2470,31 @@ impl Param {
     }
 
     pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
-        let parent = match self.func {
-            Callee::Def(CallableDefId::FunctionId(it)) => DefWithBodyId::FunctionId(it),
-            Callee::Closure(closure, _) => db.lookup_intern_closure(closure.into()).0,
-            _ => return None,
-        };
-        let body = db.body(parent);
-        if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
-            Some(Local { parent, binding_id: self_param })
-        } else if let Pat::Bind { id, .. } =
-            &body[body.params[self.idx - body.self_param.is_some() as usize]]
-        {
-            Some(Local { parent, binding_id: *id })
-        } else {
-            None
+        match self.func {
+            Callee::Def(CallableDefId::FunctionId(it)) => {
+                let parent = DefWithBodyId::FunctionId(it);
+                let body = db.body(parent);
+                if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
+                    Some(Local { parent, binding_id: self_param })
+                } else if let Pat::Bind { id, .. } =
+                    &body[body.params[self.idx - body.self_param.is_some() as usize]]
+                {
+                    Some(Local { parent, binding_id: *id })
+                } else {
+                    None
+                }
+            }
+            Callee::Closure(closure, _) => {
+                let c = db.lookup_intern_closure(closure.into());
+                let body = db.body(c.0);
+                if let Expr::Closure { args, .. } = &body[c.1] {
+                    if let Pat::Bind { id, .. } = &body[args[self.idx]] {
+                        return Some(Local { parent: c.0, binding_id: *id });
+                    }
+                }
+                None
+            }
+            _ => None,
         }
     }
 
@@ -2756,6 +2767,15 @@ impl Trait {
         traits.iter().map(|tr| Trait::from(*tr)).collect()
     }
 
+    pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq<Name>) -> Option<Function> {
+        db.trait_data(self.id).items.iter().find(|(n, _)| name == *n).and_then(
+            |&(_, it)| match it {
+                AssocItemId::FunctionId(id) => Some(Function { id }),
+                _ => None,
+            },
+        )
+    }
+
     pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
         db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
     }
@@ -4673,6 +4693,10 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool))
     }
 
+    pub fn is_str(&self) -> bool {
+        matches!(self.ty.kind(Interner), TyKind::Str)
+    }
+
     pub fn is_never(&self) -> bool {
         matches!(self.ty.kind(Interner), TyKind::Never)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 523bc6f10aa..09470bed9cf 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -1439,8 +1439,20 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
     }
 
-    pub fn resolve_known_blanket_dual_impls(&self, call: &ast::MethodCallExpr) -> Option<Function> {
-        self.analyze(call.syntax())?.resolve_known_blanket_dual_impls(self.db, call)
+    /// Env is used to derive the trait environment
+    // FIXME: better api for the trait environment
+    pub fn resolve_trait_impl_method(
+        &self,
+        env: Type,
+        trait_: Trait,
+        func: Function,
+        subst: impl IntoIterator<Item = Type>,
+    ) -> Option<Function> {
+        let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None);
+        for s in subst {
+            substs = substs.push(s.ty);
+        }
+        Some(self.db.lookup_impl_method(env.env, func.into(), substs.build()).0.into())
     }
 
     fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
@@ -1471,6 +1483,8 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
     }
 
+    // This does not resolve the method call to the correct trait impl!
+    // We should probably fix that.
     pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
         self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 6b78d7a3631..b699ccde412 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -322,68 +322,6 @@ impl SourceAnalyzer {
         }
     }
 
-    // If the method is into(), try_into(), parse(), resolve it to from, try_from, from_str.
-    pub(crate) fn resolve_known_blanket_dual_impls(
-        &self,
-        db: &dyn HirDatabase,
-        call: &ast::MethodCallExpr,
-    ) -> Option<Function> {
-        // e.g. if the method call is let b = a.into(),
-        // - receiver_type is A (type of a)
-        // - return_type is B (type of b)
-        // We will find the definition of B::from(a: A).
-        let callable = self.resolve_method_call_as_callable(db, call)?;
-        let (_, receiver_type) = callable.receiver_param(db)?;
-        let return_type = callable.return_type();
-        let (search_method, substs) = match call.name_ref()?.text().as_str() {
-            "into" => {
-                let trait_ =
-                    self.resolver.resolve_known_trait(db.upcast(), &path![core::convert::From])?;
-                (
-                    self.trait_fn(db, trait_, "from")?,
-                    hir_ty::TyBuilder::subst_for_def(db, trait_, None)
-                        .push(return_type.ty)
-                        .push(receiver_type.ty)
-                        .build(),
-                )
-            }
-            "try_into" => {
-                let trait_ = self
-                    .resolver
-                    .resolve_known_trait(db.upcast(), &path![core::convert::TryFrom])?;
-                (
-                    self.trait_fn(db, trait_, "try_from")?,
-                    hir_ty::TyBuilder::subst_for_def(db, trait_, None)
-                        // If the method is try_into() or parse(), return_type is Result<T, Error>.
-                        // Get T from type arguments of Result<T, Error>.
-                        .push(return_type.type_arguments().next()?.ty)
-                        .push(receiver_type.ty)
-                        .build(),
-                )
-            }
-            "parse" => {
-                let trait_ =
-                    self.resolver.resolve_known_trait(db.upcast(), &path![core::str::FromStr])?;
-                (
-                    self.trait_fn(db, trait_, "from_str")?,
-                    hir_ty::TyBuilder::subst_for_def(db, trait_, None)
-                        .push(return_type.type_arguments().next()?.ty)
-                        .build(),
-                )
-            }
-            _ => return None,
-        };
-
-        let found_method = self.resolve_impl_method_or_trait_def(db, search_method, substs);
-        // If found_method == search_method, the method in trait itself is resolved.
-        // It means the blanket dual impl is not found.
-        if found_method == search_method {
-            None
-        } else {
-            Some(found_method.into())
-        }
-    }
-
     pub(crate) fn resolve_expr_as_callable(
         &self,
         db: &dyn HirDatabase,
@@ -1309,18 +1247,6 @@ impl SourceAnalyzer {
         Some((trait_id, fn_id))
     }
 
-    fn trait_fn(
-        &self,
-        db: &dyn HirDatabase,
-        trait_id: TraitId,
-        method_name: &str,
-    ) -> Option<FunctionId> {
-        db.trait_data(trait_id).items.iter().find_map(|(item_name, item)| match item {
-            AssocItemId::FunctionId(t) if item_name.as_str() == method_name => Some(*t),
-            _ => None,
-        })
-    }
-
     fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
         self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index a6b8ed70c36..2ebd88edae2 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -3,7 +3,7 @@
 use either::Either;
 use hir_def::{
     db::DefDatabase,
-    item_scope::{ImportId, ImportOrExternCrate},
+    item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob},
     per_ns::Item,
     src::{HasChildSource, HasSource},
     visibility::{Visibility, VisibilityExplicitness},
@@ -55,9 +55,10 @@ impl DeclarationLocation {
 }
 
 /// Represents an outstanding module that the symbol collector must collect symbols from.
+#[derive(Debug)]
 struct SymbolCollectorWork {
     module_id: ModuleId,
-    parent: Option<DefWithBodyId>,
+    parent: Option<Name>,
 }
 
 pub struct SymbolCollector<'a> {
@@ -81,7 +82,15 @@ impl<'a> SymbolCollector<'a> {
         }
     }
 
+    pub fn new_module(db: &dyn HirDatabase, module: Module) -> Box<[FileSymbol]> {
+        let mut symbol_collector = SymbolCollector::new(db);
+        symbol_collector.collect(module);
+        symbol_collector.finish()
+    }
+
     pub fn collect(&mut self, module: Module) {
+        let _p = tracing::info_span!("SymbolCollector::collect", ?module).entered();
+        tracing::info!(?module, "SymbolCollector::collect",);
         self.edition = module.krate().edition(self.db);
 
         // The initial work is the root module we're collecting, additional work will
@@ -97,16 +106,12 @@ impl<'a> SymbolCollector<'a> {
         self.symbols.into_iter().collect()
     }
 
-    pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Box<[FileSymbol]> {
-        let mut symbol_collector = SymbolCollector::new(db);
-        symbol_collector.collect(module);
-        symbol_collector.finish()
-    }
-
     fn do_work(&mut self, work: SymbolCollectorWork) {
+        let _p = tracing::info_span!("SymbolCollector::do_work", ?work).entered();
+        tracing::info!(?work, "SymbolCollector::do_work");
         self.db.unwind_if_cancelled();
 
-        let parent_name = work.parent.and_then(|id| self.def_with_body_id_name(id));
+        let parent_name = work.parent.map(|name| name.as_str().to_smolstr());
         self.with_container_name(parent_name, |s| s.collect_from_module(work.module_id));
     }
 
@@ -116,18 +121,18 @@ impl<'a> SymbolCollector<'a> {
                 ModuleDefId::ModuleId(id) => this.push_module(id, name),
                 ModuleDefId::FunctionId(id) => {
                     this.push_decl(id, name, false);
-                    this.collect_from_body(id);
+                    this.collect_from_body(id, Some(name.clone()));
                 }
                 ModuleDefId::AdtId(AdtId::StructId(id)) => this.push_decl(id, name, false),
                 ModuleDefId::AdtId(AdtId::EnumId(id)) => this.push_decl(id, name, false),
                 ModuleDefId::AdtId(AdtId::UnionId(id)) => this.push_decl(id, name, false),
                 ModuleDefId::ConstId(id) => {
                     this.push_decl(id, name, false);
-                    this.collect_from_body(id);
+                    this.collect_from_body(id, Some(name.clone()));
                 }
                 ModuleDefId::StaticId(id) => {
                     this.push_decl(id, name, false);
-                    this.collect_from_body(id);
+                    this.collect_from_body(id, Some(name.clone()));
                 }
                 ModuleDefId::TraitId(id) => {
                     this.push_decl(id, name, false);
@@ -153,24 +158,32 @@ impl<'a> SymbolCollector<'a> {
         // Nested trees are very common, so a cache here will hit a lot.
         let import_child_source_cache = &mut FxHashMap::default();
 
-        let mut push_import = |this: &mut Self, i: ImportId, name: &Name, def: ModuleDefId| {
+        let is_explicit_import = |vis| match vis {
+            Visibility::Public => true,
+            Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
+            Visibility::Module(_, VisibilityExplicitness::Implicit) => false,
+        };
+
+        let mut push_import = |this: &mut Self, i: ImportId, name: &Name, def: ModuleDefId, vis| {
             let source = import_child_source_cache
-                .entry(i.import)
-                .or_insert_with(|| i.import.child_source(this.db.upcast()));
+                .entry(i.use_)
+                .or_insert_with(|| i.use_.child_source(this.db.upcast()));
             let Some(use_tree_src) = source.value.get(i.idx) else { return };
-            let Some(name_ptr) = use_tree_src
-                .rename()
-                .and_then(|rename| rename.name())
-                .map(Either::Left)
-                .or_else(|| use_tree_src.path()?.segment()?.name_ref().map(Either::Right))
-                .map(|it| AstPtr::new(&it))
-            else {
+            let rename = use_tree_src.rename().and_then(|rename| rename.name());
+            let name_syntax = match rename {
+                Some(name) => Some(Either::Left(name)),
+                None if is_explicit_import(vis) => {
+                    (|| use_tree_src.path()?.segment()?.name_ref().map(Either::Right))()
+                }
+                None => None,
+            };
+            let Some(name_syntax) = name_syntax else {
                 return;
             };
             let dec_loc = DeclarationLocation {
                 hir_file_id: source.file_id,
                 ptr: SyntaxNodePtr::new(use_tree_src.syntax()),
-                name_ptr,
+                name_ptr: AstPtr::new(&name_syntax),
             };
             this.symbols.insert(FileSymbol {
                 name: name.symbol().clone(),
@@ -183,23 +196,23 @@ impl<'a> SymbolCollector<'a> {
         };
 
         let push_extern_crate =
-            |this: &mut Self, i: ExternCrateId, name: &Name, def: ModuleDefId| {
+            |this: &mut Self, i: ExternCrateId, name: &Name, def: ModuleDefId, vis| {
                 let loc = i.lookup(this.db.upcast());
                 let source = loc.source(this.db.upcast());
-                let Some(name_ptr) = source
-                    .value
-                    .rename()
-                    .and_then(|rename| rename.name())
-                    .map(Either::Left)
-                    .or_else(|| source.value.name_ref().map(Either::Right))
-                    .map(|it| AstPtr::new(&it))
-                else {
+                let rename = source.value.rename().and_then(|rename| rename.name());
+
+                let name_syntax = match rename {
+                    Some(name) => Some(Either::Left(name)),
+                    None if is_explicit_import(vis) => None,
+                    None => source.value.name_ref().map(Either::Right),
+                };
+                let Some(name_syntax) = name_syntax else {
                     return;
                 };
                 let dec_loc = DeclarationLocation {
                     hir_file_id: source.file_id,
                     ptr: SyntaxNodePtr::new(source.value.syntax()),
-                    name_ptr,
+                    name_ptr: AstPtr::new(&name_syntax),
                 };
                 this.symbols.insert(FileSymbol {
                     name: name.symbol().clone(),
@@ -211,18 +224,6 @@ impl<'a> SymbolCollector<'a> {
                 });
             };
 
-        let is_explicit_import = |vis| {
-            match vis {
-                Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
-                Visibility::Module(_, VisibilityExplicitness::Implicit) => {
-                    // consider imports in the crate root explicit, as these are visibly
-                    // crate-wide anyways
-                    module_id.is_crate_root()
-                }
-                Visibility::Public => true,
-            }
-        };
-
         let def_map = module_id.def_map(self.db.upcast());
         let scope = &def_map[module_id.local_id].scope;
 
@@ -232,14 +233,14 @@ impl<'a> SymbolCollector<'a> {
 
         for (name, Item { def, vis, import }) in scope.types() {
             if let Some(i) = import {
-                if is_explicit_import(vis) {
-                    match i {
-                        ImportOrExternCrate::Import(i) => push_import(self, i, name, def),
-                        ImportOrExternCrate::ExternCrate(i) => {
-                            push_extern_crate(self, i, name, def)
-                        }
+                match i {
+                    ImportOrExternCrate::Import(i) => push_import(self, i, name, def, vis),
+                    ImportOrExternCrate::Glob(_) => (),
+                    ImportOrExternCrate::ExternCrate(i) => {
+                        push_extern_crate(self, i, name, def, vis)
                     }
                 }
+
                 continue;
             }
             // self is a declaration
@@ -248,8 +249,9 @@ impl<'a> SymbolCollector<'a> {
 
         for (name, Item { def, vis, import }) in scope.macros() {
             if let Some(i) = import {
-                if is_explicit_import(vis) {
-                    push_import(self, i, name, def.into());
+                match i {
+                    ImportOrGlob::Import(i) => push_import(self, i, name, def.into(), vis),
+                    ImportOrGlob::Glob(_) => (),
                 }
                 continue;
             }
@@ -259,8 +261,9 @@ impl<'a> SymbolCollector<'a> {
 
         for (name, Item { def, vis, import }) in scope.values() {
             if let Some(i) = import {
-                if is_explicit_import(vis) {
-                    push_import(self, i, name, def);
+                match i {
+                    ImportOrGlob::Import(i) => push_import(self, i, name, def, vis),
+                    ImportOrGlob::Glob(_) => (),
                 }
                 continue;
             }
@@ -269,7 +272,7 @@ impl<'a> SymbolCollector<'a> {
         }
 
         for const_id in scope.unnamed_consts() {
-            self.collect_from_body(const_id);
+            self.collect_from_body(const_id, None);
         }
 
         for (name, id) in scope.legacy_macros() {
@@ -285,7 +288,7 @@ impl<'a> SymbolCollector<'a> {
         }
     }
 
-    fn collect_from_body(&mut self, body_id: impl Into<DefWithBodyId>) {
+    fn collect_from_body(&mut self, body_id: impl Into<DefWithBodyId>, name: Option<Name>) {
         let body_id = body_id.into();
         let body = self.db.body(body_id);
 
@@ -294,7 +297,7 @@ impl<'a> SymbolCollector<'a> {
             for (id, _) in def_map.modules() {
                 self.work.push(SymbolCollectorWork {
                     module_id: def_map.module_id(id),
-                    parent: Some(body_id),
+                    parent: name.clone(),
                 });
             }
         }
@@ -333,24 +336,6 @@ impl<'a> SymbolCollector<'a> {
         }
     }
 
-    fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option<SmolStr> {
-        match body_id {
-            DefWithBodyId::FunctionId(id) => {
-                Some(self.db.function_data(id).name.display_no_db(self.edition).to_smolstr())
-            }
-            DefWithBodyId::StaticId(id) => {
-                Some(self.db.static_data(id).name.display_no_db(self.edition).to_smolstr())
-            }
-            DefWithBodyId::ConstId(id) => {
-                Some(self.db.const_data(id).name.as_ref()?.display_no_db(self.edition).to_smolstr())
-            }
-            DefWithBodyId::VariantId(id) => {
-                Some(self.db.enum_variant_data(id).name.display_no_db(self.edition).to_smolstr())
-            }
-            DefWithBodyId::InTypeConstId(_) => Some("in type const".into()),
-        }
-    }
-
     fn push_assoc_item(&mut self, assoc_item_id: AssocItemId, name: &Name) {
         match assoc_item_id {
             AssocItemId::FunctionId(id) => self.push_decl(id, name, true),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
index 82d8db42589..fb533077d96 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
@@ -28,6 +28,7 @@ impl AssistConfig {
             prefer_no_std: self.prefer_no_std,
             prefer_prelude: self.prefer_prelude,
             prefer_absolute: self.prefer_absolute,
+            allow_unstable: true,
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
index a5c5b08d5b0..eb784cd1226 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -159,7 +159,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
     };
     // Verify this is `bool::then` that is being called.
     let func = ctx.sema.resolve_method_call(&mcall)?;
-    if !func.name(ctx.sema.db).eq_ident("then") {
+    if func.name(ctx.sema.db) != sym::then {
         return None;
     }
     let assoc = func.as_assoc_item(ctx.sema.db)?;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index bb04a43cf96..d34cf895cd9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -343,11 +343,9 @@ fn compute_closure_type_params(
     let mut mentioned_names = mentioned_generic_params
         .iter()
         .filter_map(|param| match param {
-            hir::GenericParam::TypeParam(param) => {
-                Some(param.name(ctx.db()).unescaped().display(ctx.db()).to_smolstr())
-            }
+            hir::GenericParam::TypeParam(param) => Some(param.name(ctx.db()).as_str().to_smolstr()),
             hir::GenericParam::ConstParam(param) => {
-                Some(param.name(ctx.db()).unescaped().display(ctx.db()).to_smolstr())
+                Some(param.name(ctx.db()).as_str().to_smolstr())
             }
             hir::GenericParam::LifetimeParam(_) => None,
         })
@@ -390,7 +388,7 @@ fn compute_closure_type_params(
             let has_name = syntax
                 .descendants()
                 .filter_map(ast::NameOrNameRef::cast)
-                .any(|name| mentioned_names.contains(&*name.text()));
+                .any(|name| mentioned_names.contains(name.text().trim_start_matches("r#")));
             let mut has_new_params = false;
             if has_name {
                 syntax
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index 615b5d3f98b..d4f2ea3bd94 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -170,7 +170,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
             ),
             _ => false,
         })
-        .any(|(name, _)| name.eq_ident(variant_name.text().as_str()))
+        .any(|(name, _)| name.as_str() == variant_name.text().trim_start_matches("r#"))
 }
 
 fn extract_generic_params(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index 97321f4ec1e..7b6f76d0045 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -1672,8 +1672,8 @@ macro_rules! vec {
     () => {Vec}
 }
 fn main() {
-    let $0vec = vec![];
-    let _ = vec;
+    let $0items = vec![];
+    let _ = items;
 }
 "#,
             "Extract into variable",
@@ -1696,8 +1696,8 @@ macro_rules! vec {
     () => {Vec}
 }
 fn main() {
-    const $0VEC: Vec = vec![];
-    let _ = VEC;
+    const $0ITEMS: Vec = vec![];
+    let _ = ITEMS;
 }
 "#,
             "Extract into constant",
@@ -1720,8 +1720,8 @@ macro_rules! vec {
     () => {Vec}
 }
 fn main() {
-    static $0VEC: Vec = vec![];
-    let _ = VEC;
+    static $0ITEMS: Vec = vec![];
+    let _ = ITEMS;
 }
 "#,
             "Extract into static",
@@ -2019,8 +2019,8 @@ impl<T> Vec<T> {
 }
 
 fn foo(s: &mut S) {
-    let $0vec = &mut s.vec;
-    vec.push(0);
+    let $0items = &mut s.vec;
+    items.push(0);
 }"#,
             "Extract into variable",
         );
@@ -2106,8 +2106,8 @@ impl<T> Vec<T> {
 }
 
 fn foo(f: &mut Y) {
-    let $0vec = &mut f.field.field.vec;
-    vec.push(0);
+    let $0items = &mut f.field.field.vec;
+    items.push(0);
 }"#,
             "Extract into variable",
         );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
index 7a92d8911bf..47e4a68293f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
@@ -48,7 +48,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
     let (_, def) = module
         .scope(ctx.db(), None)
         .into_iter()
-        .find(|(name, _)| name.eq_ident(name_ref.text().as_str()))?;
+        .find(|(name, _)| name.as_str() == name_ref.text().trim_start_matches("r#"))?;
     let ScopeDef::ModuleDef(def) = def else {
         return None;
     };
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
index 8a7a06b380f..10915f8aafb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
@@ -2,7 +2,7 @@ use ide_db::{
     assists::{AssistId, AssistKind},
     base_db::AnchoredPathBuf,
 };
-use syntax::{ast, AstNode};
+use syntax::{ast, AstNode, ToSmolStr};
 
 use crate::{
     assist_context::{AssistContext, Assists},
@@ -39,7 +39,7 @@ pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     }
 
     let target = source_file.syntax().text_range();
-    let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
+    let module_name = module.name(ctx.db())?.as_str().to_smolstr();
     let path = format!("../{module_name}.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
     acc.add(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
index 9692b705929..bbf18e21948 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
@@ -61,7 +61,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                                 .string_value_unescape()
                                 .is_none() =>
                     {
-                        format_to!(buf, "{}/", name.unescaped().display(db))
+                        format_to!(buf, "{}/", name.as_str())
                     }
                     _ => (),
                 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
index 2925e2334b4..7b38c795dc8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
@@ -2,7 +2,7 @@ use ide_db::{
     assists::{AssistId, AssistKind},
     base_db::AnchoredPathBuf,
 };
-use syntax::{ast, AstNode};
+use syntax::{ast, AstNode, ToSmolStr};
 
 use crate::{
     assist_context::{AssistContext, Assists},
@@ -39,7 +39,7 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     }
 
     let target = source_file.syntax().text_range();
-    let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
+    let module_name = module.name(ctx.db())?.as_str().to_smolstr();
     let path = format!("./{module_name}/mod.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
     acc.add(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
index 849b8a42c69..2a8465f634c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
@@ -208,7 +208,7 @@ fn find_trait_method(
     if let Some(hir::AssocItem::Function(method)) =
         trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
             item.name(db)
-                .map(|name| name.eq_ident(trait_method_name.text().as_str()))
+                .map(|name| name.as_str() == trait_method_name.text().trim_start_matches("r#"))
                 .unwrap_or(false)
         })
     {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
index 972303c2a04..a79a82be450 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
@@ -110,7 +110,7 @@ fn compute_fields_ranks(
         .fields(ctx.db())
         .into_iter()
         .enumerate()
-        .map(|(idx, field)| (field.name(ctx.db()).unescaped().display(ctx.db()).to_string(), idx))
+        .map(|(idx, field)| (field.name(ctx.db()).as_str().to_owned(), idx))
         .collect();
 
     Some(res)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
index eb1d538f874..c3404173eaf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
@@ -122,7 +122,7 @@ fn compute_item_ranks(
             .iter()
             .flat_map(|i| i.name(ctx.db()))
             .enumerate()
-            .map(|(idx, name)| (name.unescaped().display(ctx.db()).to_string(), idx))
+            .map(|(idx, name)| (name.as_str().to_owned(), idx))
             .collect(),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index 40669c65c57..a22e7b272ea 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -188,9 +188,6 @@ impl Completions {
         resolution: hir::ScopeDef,
         doc_aliases: Vec<syntax::SmolStr>,
     ) {
-        if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) {
-            return;
-        }
         let is_private_editable = match ctx.def_is_visible(&resolution) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -216,9 +213,6 @@ impl Completions {
         local_name: hir::Name,
         resolution: hir::ScopeDef,
     ) {
-        if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) {
-            return;
-        }
         let is_private_editable = match ctx.def_is_visible(&resolution) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -241,7 +235,7 @@ impl Completions {
         path_ctx: &PathCompletionCtx,
         e: hir::Enum,
     ) {
-        if !ctx.check_stability(Some(&e.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(e) {
             return;
         }
         e.variants(ctx.db)
@@ -257,9 +251,6 @@ impl Completions {
         local_name: hir::Name,
         doc_aliases: Vec<syntax::SmolStr>,
     ) {
-        if !ctx.check_stability(Some(&module.attrs(ctx.db))) {
-            return;
-        }
         self.add_path_resolution(
             ctx,
             path_ctx,
@@ -276,9 +267,6 @@ impl Completions {
         mac: hir::Macro,
         local_name: hir::Name,
     ) {
-        if !ctx.check_stability(Some(&mac.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&mac) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -302,9 +290,6 @@ impl Completions {
         func: hir::Function,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&func) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -332,9 +317,6 @@ impl Completions {
         receiver: Option<SmolStr>,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&func) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -362,9 +344,6 @@ impl Completions {
         func: hir::Function,
         import: LocatedImport,
     ) {
-        if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&func) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -387,9 +366,6 @@ impl Completions {
     }
 
     pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) {
-        if !ctx.check_stability(Some(&konst.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&konst) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -406,9 +382,6 @@ impl Completions {
         ctx: &CompletionContext<'_>,
         type_alias: hir::TypeAlias,
     ) {
-        if !ctx.check_stability(Some(&type_alias.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&type_alias) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -438,7 +411,7 @@ impl Completions {
         variant: hir::Variant,
         path: hir::ModPath,
     ) {
-        if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(variant) {
             return;
         }
         if let Some(builder) =
@@ -455,7 +428,7 @@ impl Completions {
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(variant) {
             return;
         }
         if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
@@ -479,9 +452,6 @@ impl Completions {
         field: hir::Field,
         ty: &hir::Type,
     ) {
-        if !ctx.check_stability(Some(&field.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&field) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -506,12 +476,18 @@ impl Completions {
         path: Option<hir::ModPath>,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) {
-            return;
-        }
-        if let Some(builder) =
-            render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name)
-        {
+        let is_private_editable = match ctx.is_visible(&strukt) {
+            Visible::Yes => false,
+            Visible::Editable => true,
+            Visible::No => return,
+        };
+        if let Some(builder) = render_struct_literal(
+            RenderContext::new(ctx).private_editable(is_private_editable),
+            path_ctx,
+            strukt,
+            path,
+            local_name,
+        ) {
             self.add(builder.build(ctx.db));
         }
     }
@@ -523,10 +499,17 @@ impl Completions {
         path: Option<hir::ModPath>,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&un.attrs(ctx.db))) {
-            return;
-        }
-        let item = render_union_literal(RenderContext::new(ctx), un, path, local_name);
+        let is_private_editable = match ctx.is_visible(&un) {
+            Visible::Yes => false,
+            Visible::Editable => true,
+            Visible::No => return,
+        };
+        let item = render_union_literal(
+            RenderContext::new(ctx).private_editable(is_private_editable),
+            un,
+            path,
+            local_name,
+        );
         self.add_opt(item);
     }
 
@@ -571,7 +554,7 @@ impl Completions {
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(variant) {
             return;
         }
         self.add_opt(render_variant_pat(
@@ -591,7 +574,7 @@ impl Completions {
         variant: hir::Variant,
         path: hir::ModPath,
     ) {
-        if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(variant) {
             return;
         }
         let path = Some(&path);
@@ -612,10 +595,17 @@ impl Completions {
         strukt: hir::Struct,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) {
-            return;
-        }
-        self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
+        let is_private_editable = match ctx.is_visible(&strukt) {
+            Visible::Yes => false,
+            Visible::Editable => true,
+            Visible::No => return,
+        };
+        self.add_opt(render_struct_pat(
+            RenderContext::new(ctx).private_editable(is_private_editable),
+            pattern_ctx,
+            strukt,
+            local_name,
+        ));
     }
 
     pub(crate) fn suggest_name(&mut self, ctx: &CompletionContext<'_>, name: &str) {
@@ -660,7 +650,7 @@ fn enum_variants_with_paths(
         if let Some(path) = ctx.module.find_path(
             ctx.db,
             hir::ModuleDef::from(variant),
-            ctx.config.import_path_config(),
+            ctx.config.import_path_config(ctx.is_nightly),
         ) {
             // Variants with trivial paths are already added by the existing completion logic,
             // so we should avoid adding these twice
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 7679d9076de..d12654665ce 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
@@ -42,31 +42,38 @@ pub(crate) fn complete_dot(
         item.detail("expr.await");
         item.add_to(acc, ctx.db);
 
-        // Completions that skip `.await`, e.g. `.await.foo()`.
-        let dot_access_kind = match &dot_access.kind {
-            DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
-                DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
-            }
-            it @ DotAccessKind::Method { .. } => *it,
-        };
-        let dot_access = DotAccess {
-            receiver: dot_access.receiver.clone(),
-            receiver_ty: Some(hir::TypeInfo { original: future_output.clone(), adjusted: None }),
-            kind: dot_access_kind,
-            ctx: dot_access.ctx,
-        };
-        complete_fields(
-            acc,
-            ctx,
-            &future_output,
-            |acc, field, ty| acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty),
-            |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
-            is_field_access,
-            is_method_access_with_parens,
-        );
-        complete_methods(ctx, &future_output, &traits_in_scope, |func| {
-            acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
-        });
+        if ctx.config.enable_auto_await {
+            // Completions that skip `.await`, e.g. `.await.foo()`.
+            let dot_access_kind = match &dot_access.kind {
+                DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+                    DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+                }
+                it @ DotAccessKind::Method { .. } => *it,
+            };
+            let dot_access = DotAccess {
+                receiver: dot_access.receiver.clone(),
+                receiver_ty: Some(hir::TypeInfo {
+                    original: future_output.clone(),
+                    adjusted: None,
+                }),
+                kind: dot_access_kind,
+                ctx: dot_access.ctx,
+            };
+            complete_fields(
+                acc,
+                ctx,
+                &future_output,
+                |acc, field, ty| {
+                    acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty)
+                },
+                |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
+                is_field_access,
+                is_method_access_with_parens,
+            );
+            complete_methods(ctx, &future_output, &traits_in_scope, |func| {
+                acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
+            });
+        }
     }
 
     complete_fields(
@@ -82,39 +89,41 @@ pub(crate) fn complete_dot(
         acc.add_method(ctx, dot_access, func, None, None)
     });
 
-    // FIXME:
-    // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
-    // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
-    // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
-    let iter = receiver_ty
-        .strip_references()
-        .add_reference(hir::Mutability::Shared)
-        .into_iterator_iter(ctx.db)
-        .map(|ty| (ty, SmolStr::new_static("iter()")));
-    // Does <receiver_ty as IntoIterator>::IntoIter` exist?
-    let into_iter = || {
-        receiver_ty
-            .clone()
+    if ctx.config.enable_auto_iter {
+        // FIXME:
+        // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
+        // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
+        // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
+        let iter = receiver_ty
+            .strip_references()
+            .add_reference(hir::Mutability::Shared)
             .into_iterator_iter(ctx.db)
-            .map(|ty| (ty, SmolStr::new_static("into_iter()")))
-    };
-    if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
-        // Skip iterators, e.g. complete `.iter().filter_map()`.
-        let dot_access_kind = match &dot_access.kind {
-            DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
-                DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
-            }
-            it @ DotAccessKind::Method { .. } => *it,
+            .map(|ty| (ty, SmolStr::new_static("iter()")));
+        // Does <receiver_ty as IntoIterator>::IntoIter` exist?
+        let into_iter = || {
+            receiver_ty
+                .clone()
+                .into_iterator_iter(ctx.db)
+                .map(|ty| (ty, SmolStr::new_static("into_iter()")))
         };
-        let dot_access = DotAccess {
-            receiver: dot_access.receiver.clone(),
-            receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
-            kind: dot_access_kind,
-            ctx: dot_access.ctx,
-        };
-        complete_methods(ctx, &iter, &traits_in_scope, |func| {
-            acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
-        });
+        if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
+            // Skip iterators, e.g. complete `.iter().filter_map()`.
+            let dot_access_kind = match &dot_access.kind {
+                DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+                    DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+                }
+                it @ DotAccessKind::Method { .. } => *it,
+            };
+            let dot_access = DotAccess {
+                receiver: dot_access.receiver.clone(),
+                receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
+                kind: dot_access_kind,
+                ctx: dot_access.ctx,
+            };
+            complete_methods(ctx, &iter, &traits_in_scope, |func| {
+                acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
+            });
+        }
     }
 }
 
@@ -1466,4 +1475,34 @@ async fn bar() {
 "#,
         );
     }
+
+    #[test]
+    fn receiver_without_deref_impl_completion() {
+        check_no_kw(
+            r#"
+//- minicore: receiver
+use core::ops::Receiver;
+
+struct Foo;
+
+impl Foo {
+    fn foo(self: Bar) {}
+}
+
+struct Bar;
+
+impl Receiver for Bar {
+    type Target = Foo;
+}
+
+fn main() {
+    let bar = Bar;
+    bar.$0
+}
+"#,
+            expect![[r#"
+    me foo() fn(self: Bar)
+"#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index db18b531d7c..e7101751701 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -247,7 +247,7 @@ pub(crate) fn complete_expr_path(
                             .find_path(
                                 ctx.db,
                                 hir::ModuleDef::from(strukt),
-                                ctx.config.import_path_config(),
+                                ctx.config.import_path_config(ctx.is_nightly),
                             )
                             .filter(|it| it.len() > 1);
 
@@ -269,7 +269,7 @@ pub(crate) fn complete_expr_path(
                             .find_path(
                                 ctx.db,
                                 hir::ModuleDef::from(un),
-                                ctx.config.import_path_config(),
+                                ctx.config.import_path_config(ctx.is_nightly),
                             )
                             .filter(|it| it.len() > 1);
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index 73313eeaa6b..24243f57b46 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -5,7 +5,7 @@ use ide_db::imports::{
     insert_use::ImportScope,
 };
 use itertools::Itertools;
-use syntax::{ast, AstNode, SyntaxNode, ToSmolStr};
+use syntax::{ast, AstNode, SyntaxNode};
 
 use crate::{
     config::AutoImportExclusionType,
@@ -257,7 +257,7 @@ fn import_on_the_fly(
     };
     let user_input_lowercased = potential_import_name.to_lowercase();
 
-    let import_cfg = ctx.config.import_path_config();
+    let import_cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     import_assets
         .search_for_imports(&ctx.sema, import_cfg, ctx.config.insert_use.prefix_kind)
@@ -316,7 +316,7 @@ fn import_on_the_fly_pat_(
         ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)),
     };
     let user_input_lowercased = potential_import_name.to_lowercase();
-    let cfg = ctx.config.import_path_config();
+    let cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     import_assets
         .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
@@ -358,7 +358,7 @@ fn import_on_the_fly_method(
 
     let user_input_lowercased = potential_import_name.to_lowercase();
 
-    let cfg = ctx.config.import_path_config();
+    let cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     import_assets
         .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
@@ -444,7 +444,7 @@ fn compute_fuzzy_completion_order_key(
     cov_mark::hit!(certain_fuzzy_order_test);
     let import_name = match proposed_mod_path.segments().last() {
         // FIXME: nasty alloc, this is a hot path!
-        Some(name) => name.unescaped().display_no_db().to_smolstr().to_ascii_lowercase(),
+        Some(name) => name.as_str().to_ascii_lowercase(),
         None => return usize::MAX,
     };
     match import_name.match_indices(user_input_lowercased).next() {
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 6d1945c4534..831f5665f4a 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
@@ -31,7 +31,7 @@
 //! }
 //! ```
 
-use hir::{db::ExpandDatabase, HasAttrs, MacroFileId, Name};
+use hir::{db::ExpandDatabase, MacroFileId, Name};
 use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::HasDocs, path_transform::PathTransform,
@@ -85,7 +85,7 @@ fn complete_trait_impl_name(
     name: &Option<ast::Name>,
     kind: ImplCompletionKind,
 ) -> Option<()> {
-    let item = match name {
+    let macro_file_item = match name {
         Some(name) => name.syntax().parent(),
         None => {
             let token = &ctx.token;
@@ -96,12 +96,12 @@ fn complete_trait_impl_name(
             .parent()
         }
     }?;
-    let item = ctx.sema.original_syntax_node_rooted(&item)?;
+    let real_file_item = ctx.sema.original_syntax_node_rooted(&macro_file_item)?;
     // item -> ASSOC_ITEM_LIST -> IMPL
-    let impl_def = ast::Impl::cast(item.parent()?.parent()?)?;
+    let impl_def = ast::Impl::cast(macro_file_item.parent()?.parent()?)?;
     let replacement_range = {
         // ctx.sema.original_ast_node(item)?;
-        let first_child = item
+        let first_child = real_file_item
             .children_with_tokens()
             .find(|child| {
                 !matches!(
@@ -109,7 +109,7 @@ fn complete_trait_impl_name(
                     SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR
                 )
             })
-            .unwrap_or_else(|| SyntaxElement::Node(item.clone()));
+            .unwrap_or_else(|| SyntaxElement::Node(real_file_item.clone()));
 
         TextRange::new(first_child.text_range().start(), ctx.source_range().end())
     };
@@ -133,8 +133,11 @@ pub(crate) fn complete_trait_impl_item_by_name(
             acc,
             ctx,
             ImplCompletionKind::All,
-            match name_ref {
-                Some(name) => name.syntax().text_range(),
+            match name_ref
+                .as_ref()
+                .and_then(|name| ctx.sema.original_syntax_node_rooted(name.syntax()))
+            {
+                Some(name) => name.text_range(),
                 None => ctx.source_range(),
             },
             impl_,
@@ -152,7 +155,7 @@ fn complete_trait_impl(
     if let Some(hir_impl) = ctx.sema.to_def(impl_def) {
         get_missing_assoc_items(&ctx.sema, impl_def)
             .into_iter()
-            .filter(|item| ctx.check_stability(Some(&item.attrs(ctx.db))))
+            .filter(|item| ctx.check_stability_and_hidden(*item))
             .for_each(|item| {
                 use self::ImplCompletionKind::*;
                 match (item, kind) {
@@ -359,7 +362,7 @@ fn add_type_alias_impl(
     type_alias: hir::TypeAlias,
     impl_def: hir::Impl,
 ) {
-    let alias_name = type_alias.name(ctx.db).unescaped().display(ctx.db).to_smolstr();
+    let alias_name = type_alias.name(ctx.db).as_str().to_smolstr();
 
     let label = format_smolstr!("type {alias_name} =");
 
@@ -516,7 +519,7 @@ fn function_declaration(
 mod tests {
     use expect_test::expect;
 
-    use crate::tests::{check_edit, check_no_kw};
+    use crate::tests::{check, check_edit, check_no_kw};
 
     #[test]
     fn no_completion_inside_fn() {
@@ -1639,4 +1642,51 @@ impl DesugaredAsyncTrait for () {
 "#,
         );
     }
+
+    #[test]
+    fn within_attr_macro() {
+        check(
+            r#"
+//- proc_macros: identity
+trait Trait {
+    fn foo(&self) {}
+    fn bar(&self) {}
+    fn baz(&self) {}
+}
+
+#[proc_macros::identity]
+impl Trait for () {
+    f$0
+}
+                "#,
+            expect![[r#"
+                me fn bar(..)
+                me fn baz(..)
+                me fn foo(..)
+                md proc_macros
+                kw crate::
+                kw self::
+            "#]],
+        );
+        check(
+            r#"
+//- proc_macros: identity
+trait Trait {
+    fn foo(&self) {}
+    fn bar(&self) {}
+    fn baz(&self) {}
+}
+
+#[proc_macros::identity]
+impl Trait for () {
+    fn $0
+}
+        "#,
+            expect![[r#"
+                me fn bar(..)
+                me fn baz(..)
+                me fn foo(..)
+            "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
index bafe3294209..cca6a22f290 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
@@ -7,7 +7,7 @@ use ide_db::{
     base_db::{SourceRootDatabase, VfsPath},
     FxHashSet, RootDatabase, SymbolKind,
 };
-use syntax::{ast, AstNode, SyntaxKind, ToSmolStr};
+use syntax::{ast, AstNode, SyntaxKind};
 
 use crate::{context::CompletionContext, CompletionItem, Completions};
 
@@ -140,9 +140,7 @@ fn directory_to_look_for_submodules(
     module_chain_to_containing_module_file(module, db)
         .into_iter()
         .filter_map(|module| module.name(db))
-        .try_fold(base_directory, |path, name| {
-            path.join(&name.unescaped().display_no_db().to_smolstr())
-        })
+        .try_fold(base_directory, |path, name| path.join(name.as_str()))
 }
 
 fn module_chain_to_containing_module_file(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 67ea05e002b..2c39a8fdfed 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -60,7 +60,7 @@ pub(crate) fn complete_postfix(
         None => return,
     };
 
-    let cfg = ctx.config.import_path_config();
+    let cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
         if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
index 9d62622add2..b384987c51c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
@@ -52,8 +52,14 @@ pub(crate) fn complete_use_path(
                         )
                     };
                     for (name, def) in module_scope {
-                        if !ctx.check_stability(def.attrs(ctx.db).as_deref()) {
-                            continue;
+                        if let (Some(attrs), Some(defining_crate)) =
+                            (def.attrs(ctx.db), def.krate(ctx.db))
+                        {
+                            if !ctx.check_stability(Some(&attrs))
+                                || ctx.is_doc_hidden(&attrs, defining_crate)
+                            {
+                                continue;
+                            }
                         }
                         let is_name_already_imported =
                             already_imported_names.contains(name.as_str());
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
index 8b1ce11e8a4..45aab38e8ea 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
@@ -14,6 +14,8 @@ pub struct CompletionConfig<'a> {
     pub enable_postfix_completions: bool,
     pub enable_imports_on_the_fly: bool,
     pub enable_self_on_the_fly: bool,
+    pub enable_auto_iter: bool,
+    pub enable_auto_await: bool,
     pub enable_private_editable: bool,
     pub enable_term_search: bool,
     pub term_search_fuel: u64,
@@ -57,11 +59,12 @@ impl CompletionConfig<'_> {
             .flat_map(|snip| snip.prefix_triggers.iter().map(move |trigger| (&**trigger, snip)))
     }
 
-    pub fn import_path_config(&self) -> ImportPathConfig {
+    pub fn import_path_config(&self, allow_unstable: bool) -> ImportPathConfig {
         ImportPathConfig {
             prefer_no_std: self.prefer_no_std,
             prefer_prelude: self.prefer_prelude,
             prefer_absolute: self.prefer_absolute,
+            allow_unstable,
         }
     }
 }
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 3a2a4a23a19..2f1860cbb59 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -443,7 +443,9 @@ pub(crate) struct CompletionContext<'a> {
     /// The module of the `scope`.
     pub(crate) module: hir::Module,
     /// Whether nightly toolchain is used. Cached since this is looked up a lot.
-    is_nightly: bool,
+    pub(crate) is_nightly: bool,
+    /// The edition of the current crate
+    // FIXME: This should probably be the crate of the current token?
     pub(crate) edition: Edition,
 
     /// The expected name of what we are completing.
@@ -532,7 +534,7 @@ impl CompletionContext<'_> {
         }
     }
 
-    /// Checks if an item is visible and not `doc(hidden)` at the completion site.
+    /// Checks if an item is visible, not `doc(hidden)` and stable at the completion site.
     pub(crate) fn is_visible<I>(&self, item: &I) -> Visible
     where
         I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
@@ -568,6 +570,15 @@ impl CompletionContext<'_> {
         !attrs.is_unstable() || self.is_nightly
     }
 
+    pub(crate) fn check_stability_and_hidden<I>(&self, item: I) -> bool
+    where
+        I: hir::HasAttrs + hir::HasCrate,
+    {
+        let defining_crate = item.krate(self.db);
+        let attrs = item.attrs(self.db);
+        self.check_stability(Some(&attrs)) && !self.is_doc_hidden(&attrs, defining_crate)
+    }
+
     /// 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() {
@@ -645,6 +656,10 @@ impl CompletionContext<'_> {
         attrs: &hir::Attrs,
         defining_crate: hir::Crate,
     ) -> Visible {
+        if !self.check_stability(Some(attrs)) {
+            return Visible::No;
+        }
+
         if !vis.is_visible_from(self.db, self.module.into()) {
             if !self.config.enable_private_editable {
                 return Visible::No;
@@ -664,7 +679,7 @@ impl CompletionContext<'_> {
         }
     }
 
-    fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
+    pub(crate) fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
         // `doc(hidden)` items are only completed within the defining crate.
         self.krate != defining_crate && attrs.has_doc_hidden()
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 3c4d489c0ff..f5a50ae8190 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -5,7 +5,7 @@ use hir::{ExpandResult, Semantics, Type, TypeInfo, Variant};
 use ide_db::{active_parameter::ActiveParameter, RootDatabase};
 use itertools::Either;
 use syntax::{
-    algo::{ancestors_at_offset, find_node_at_offset, non_trivia_sibling},
+    algo::{self, ancestors_at_offset, find_node_at_offset, non_trivia_sibling},
     ast::{
         self, AttrKind, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName,
         NameOrNameRef,
@@ -85,6 +85,11 @@ pub(super) fn expand_and_analyze(
     })
 }
 
+fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Option<SyntaxToken> {
+    let token = file.token_at_offset(offset).left_biased()?;
+    algo::skip_whitespace_token(token, Direction::Prev)
+}
+
 /// Expand attributes and macro calls at the current cursor position for both the original file
 /// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
 /// and speculative states stay in sync.
@@ -125,9 +130,7 @@ fn expand(
 
     // Left biased since there may already be an identifier token there, and we appended to it.
     if !sema.might_be_inside_macro_call(&fake_ident_token)
-        && original_file
-            .token_at_offset(original_offset + relative_offset)
-            .left_biased()
+        && token_at_offset_ignore_whitespace(&original_file, original_offset + relative_offset)
             .is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token))
     {
         // Recursion base case.
@@ -143,9 +146,11 @@ fn expand(
 
     let parent_item =
         |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
+    let original_node = token_at_offset_ignore_whitespace(&original_file, original_offset)
+        .and_then(|token| token.parent_ancestors().find_map(ast::Item::cast));
     let ancestor_items = iter::successors(
         Option::zip(
-            find_node_at_offset::<ast::Item>(&original_file, original_offset),
+            original_node,
             find_node_at_offset::<ast::Item>(
                 &speculative_file,
                 fake_ident_token.text_range().start(),
@@ -1590,11 +1595,11 @@ fn pattern_context_for(
                                         }).map(|enum_| enum_.variants(sema.db))
                                     })
                                 }).map(|variants| variants.iter().filter_map(|variant| {
-                                        let variant_name = variant.name(sema.db).unescaped().display(sema.db).to_string();
+                                        let variant_name = variant.name(sema.db);
 
                                         let variant_already_present = match_arm_list.arms().any(|arm| {
                                             arm.pat().and_then(|pat| {
-                                                let pat_already_present = pat.syntax().to_string().contains(&variant_name);
+                                                let pat_already_present = pat.syntax().to_string().contains(variant_name.as_str());
                                                 pat_already_present.then_some(pat_already_present)
                                             }).is_some()
                                         });
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 dc2f9a76802..41a82409597 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -82,8 +82,7 @@ pub struct CompletionItem {
     pub ref_match: Option<(CompletionItemRefMode, TextSize)>,
 
     /// The import data to add to completion's edits.
-    /// (ImportPath, LastSegment)
-    pub import_to_add: SmallVec<[(String, String); 1]>,
+    pub import_to_add: SmallVec<[String; 1]>,
 }
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
@@ -181,6 +180,8 @@ pub struct CompletionRelevance {
     pub postfix_match: Option<CompletionRelevancePostfixMatch>,
     /// This is set for items that are function (associated or method)
     pub function: Option<CompletionRelevanceFn>,
+    /// true when there is an `await.method()` or `iter().method()` completion.
+    pub is_skipping_completion: bool,
 }
 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
 pub struct CompletionRelevanceTraitInfo {
@@ -269,6 +270,7 @@ impl CompletionRelevance {
             postfix_match,
             trait_,
             function,
+            is_skipping_completion,
         } = self;
 
         // only applicable for completions within use items
@@ -296,6 +298,12 @@ impl CompletionRelevance {
                 score -= 5;
             }
         }
+
+        // Lower rank for completions that skip `await` and `iter()`.
+        if is_skipping_completion {
+            score -= 7;
+        }
+
         // lower rank for items that need an import
         if requires_import {
             score -= 1;
@@ -561,12 +569,7 @@ impl Builder {
         let import_to_add = self
             .imports_to_add
             .into_iter()
-            .filter_map(|import| {
-                Some((
-                    import.import_path.display(db, self.edition).to_string(),
-                    import.import_path.segments().last()?.display(db, self.edition).to_string(),
-                ))
-            })
+            .map(|import| import.import_path.display(db, self.edition).to_string())
             .collect();
 
         CompletionItem {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index 56d7eeaf8ea..8051d48ca5f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -10,17 +10,13 @@ mod snippet;
 #[cfg(test)]
 mod tests;
 
-use ide_db::text_edit::TextEdit;
 use ide_db::{
-    helpers::mod_path_to_ast,
-    imports::{
-        import_assets::NameToImport,
-        insert_use::{self, ImportScope},
-    },
-    items_locator,
+    imports::insert_use::{self, ImportScope},
     syntax_helpers::tree_diff::diff,
+    text_edit::TextEdit,
     FilePosition, FxHashSet, RootDatabase,
 };
+use syntax::ast::make;
 
 use crate::{
     completions::Completions,
@@ -272,7 +268,7 @@ pub fn resolve_completion_edits(
     db: &RootDatabase,
     config: &CompletionConfig<'_>,
     FilePosition { file_id, offset }: FilePosition,
-    imports: impl IntoIterator<Item = (String, String)>,
+    imports: impl IntoIterator<Item = String>,
 ) -> Option<Vec<TextEdit>> {
     let _p = tracing::info_span!("resolve_completion_edits").entered();
     let sema = hir::Semantics::new(db);
@@ -289,27 +285,12 @@ pub fn resolve_completion_edits(
     let new_ast = scope.clone_for_update();
     let mut import_insert = TextEdit::builder();
 
-    let cfg = config.import_path_config();
-
-    imports.into_iter().for_each(|(full_import_path, imported_name)| {
-        let items_with_name = items_locator::items_with_name(
-            &sema,
-            current_crate,
-            NameToImport::exact_case_sensitive(imported_name),
-            items_locator::AssocSearchMode::Include,
+    imports.into_iter().for_each(|full_import_path| {
+        insert_use::insert_use(
+            &new_ast,
+            make::path_from_text_with_edition(&full_import_path, current_edition),
+            &config.insert_use,
         );
-        let import = items_with_name
-            .filter_map(|candidate| {
-                current_module.find_use_path(db, candidate, config.insert_use.prefix_kind, cfg)
-            })
-            .find(|mod_path| mod_path.display(db, current_edition).to_string() == full_import_path);
-        if let Some(import_path) = import {
-            insert_use::insert_use(
-                &new_ast,
-                mod_path_to_ast(&import_path, current_edition),
-                &config.insert_use,
-            );
-        }
     });
 
     diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
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 61e8114d381..dc7eacbfbaf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -130,10 +130,8 @@ pub(crate) fn render_field(
     let db = ctx.db();
     let is_deprecated = ctx.is_deprecated(field);
     let name = field.name(db);
-    let (name, escaped_name) = (
-        name.unescaped().display(db).to_smolstr(),
-        name.display_no_db(ctx.completion.edition).to_smolstr(),
-    );
+    let (name, escaped_name) =
+        (name.as_str().to_smolstr(), name.display_no_db(ctx.completion.edition).to_smolstr());
     let mut item = CompletionItem::new(
         SymbolKind::Field,
         ctx.source_range(),
@@ -142,7 +140,8 @@ pub(crate) fn render_field(
     );
     item.set_relevance(CompletionRelevance {
         type_match: compute_type_match(ctx.completion, ty),
-        exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
+        exact_name_match: compute_exact_name_match(ctx.completion, &name),
+        is_skipping_completion: receiver.is_some(),
         ..CompletionRelevance::default()
     });
     item.detail(ty.display(db, ctx.completion.edition).to_string())
@@ -215,6 +214,10 @@ pub(crate) fn render_tuple_field(
     );
     item.detail(ty.display(ctx.db(), ctx.completion.edition).to_string())
         .lookup_by(field.to_string());
+    item.set_relevance(CompletionRelevance {
+        is_skipping_completion: receiver.is_some(),
+        ..ctx.completion_relevance()
+    });
     item.build(ctx.db())
 }
 
@@ -298,7 +301,7 @@ pub(crate) fn render_expr(
             .unwrap_or_else(|| String::from("..."))
     };
 
-    let cfg = ctx.config.import_path_config();
+    let cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.edition).ok()?;
 
@@ -512,7 +515,7 @@ fn render_resolution_simple_(
     let mut item = CompletionItem::new(
         kind,
         ctx.source_range(),
-        local_name.unescaped().display(db).to_smolstr(),
+        local_name.as_str().to_smolstr(),
         ctx.completion.edition,
     );
     item.set_relevance(ctx.completion_relevance())
@@ -1335,6 +1338,7 @@ fn main() { let _: m::Spam = S$0 }
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                         trigger_call_info: true,
                     },
@@ -1364,6 +1368,7 @@ fn main() { let _: m::Spam = S$0 }
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                         trigger_call_info: true,
                     },
@@ -1453,6 +1458,7 @@ fn foo() { A { the$0 } }
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                 ]
@@ -1511,6 +1517,7 @@ impl S {
                                     return_type: Other,
                                 },
                             ),
+                            is_skipping_completion: false,
                         },
                     },
                     CompletionItem {
@@ -1653,6 +1660,7 @@ fn foo(s: S) { s.$0 }
                                     return_type: Other,
                                 },
                             ),
+                            is_skipping_completion: false,
                         },
                     },
                 ]
@@ -1864,6 +1872,7 @@ fn f() -> i32 {
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                 ]
@@ -2624,6 +2633,7 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
                                     return_type: Other,
                                 },
                             ),
+                            is_skipping_completion: false,
                         },
                         ref_match: "&@107",
                     },
@@ -2709,6 +2719,7 @@ fn foo() {
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                 ]
@@ -2766,6 +2777,7 @@ fn main() {
                                     return_type: Other,
                                 },
                             ),
+                            is_skipping_completion: false,
                         },
                         ref_match: "&@92",
                     },
@@ -3140,6 +3152,7 @@ fn main() {
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                     CompletionItem {
@@ -3173,6 +3186,7 @@ fn main() {
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                 ]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
index 415d87c6239..e357ab24d22 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
@@ -14,10 +14,8 @@ pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option
 fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
     let db = ctx.db();
     let name = const_.name(db)?;
-    let (name, escaped_name) = (
-        name.unescaped().display(db).to_smolstr(),
-        name.display(db, ctx.completion.edition).to_smolstr(),
-    );
+    let (name, escaped_name) =
+        (name.as_str().to_smolstr(), name.display(db, ctx.completion.edition).to_smolstr());
     let detail = const_.display(db, ctx.completion.edition).to_string();
 
     let mut item =
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 3b97d67169e..c3354902c3b 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
@@ -59,13 +59,10 @@ fn render(
 
     let (call, escaped_call) = match &func_kind {
         FuncKind::Method(_, Some(receiver)) => (
-            format_smolstr!("{}.{}", receiver, name.unescaped().display(ctx.db())),
+            format_smolstr!("{}.{}", receiver, name.as_str()),
             format_smolstr!("{}.{}", receiver, name.display(ctx.db(), completion.edition)),
         ),
-        _ => (
-            name.unescaped().display(db).to_smolstr(),
-            name.display(db, completion.edition).to_smolstr(),
-        ),
+        _ => (name.as_str().to_smolstr(), name.display(db, completion.edition).to_smolstr()),
     };
     let has_self_param = func.self_param(db).is_some();
     let mut item = CompletionItem::new(
@@ -126,6 +123,7 @@ fn render(
         exact_name_match: compute_exact_name_match(completion, &call),
         function,
         trait_: trait_info,
+        is_skipping_completion: matches!(func_kind, FuncKind::Method(_, Some(_))),
         ..ctx.completion_relevance()
     });
 
@@ -151,7 +149,7 @@ fn render(
     item.set_documentation(ctx.docs(func))
         .set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func))
         .detail(detail)
-        .lookup_by(name.unescaped().display(db).to_smolstr());
+        .lookup_by(name.as_str().to_smolstr());
 
     if let Some((cap, (self_param, params))) = complete_call_parens {
         add_call_parens(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index c71356e5300..aab54ca5e01 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -75,7 +75,7 @@ fn render(
         None => (name.clone().into(), name.into(), false),
     };
     let (qualified_name, escaped_qualified_name) = (
-        qualified_name.unescaped().display(ctx.db()).to_string(),
+        qualified_name.display_verbatim(ctx.db()).to_string(),
         qualified_name.display(ctx.db(), completion.edition).to_string(),
     );
     let snippet_cap = ctx.snippet_cap();
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index 6490171fbb4..e265e92f979 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -46,21 +46,19 @@ fn render(
         ctx.source_range()
     };
 
-    let (name, escaped_name) = (
-        name.unescaped().display(ctx.db()).to_smolstr(),
-        name.display(ctx.db(), completion.edition).to_smolstr(),
-    );
+    let (name, escaped_name) =
+        (name.as_str(), name.display(ctx.db(), completion.edition).to_smolstr());
     let docs = ctx.docs(macro_);
     let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default();
     let is_fn_like = macro_.is_fn_like(completion.db);
-    let (bra, ket) = if is_fn_like { guess_macro_braces(&name, docs_str) } else { ("", "") };
+    let (bra, ket) = if is_fn_like { guess_macro_braces(name, docs_str) } else { ("", "") };
 
     let needs_bang = is_fn_like && !is_use_path && !has_macro_bang;
 
     let mut item = CompletionItem::new(
         SymbolKind::from(macro_.kind(completion.db)),
         source_range,
-        label(&ctx, needs_bang, bra, ket, &name),
+        label(&ctx, needs_bang, bra, ket, &name.to_smolstr()),
         completion.edition,
     );
     item.set_deprecated(ctx.is_deprecated(macro_))
@@ -71,11 +69,11 @@ fn render(
     match ctx.snippet_cap() {
         Some(cap) if needs_bang && !has_call_parens => {
             let snippet = format!("{escaped_name}!{bra}$0{ket}");
-            let lookup = banged_name(&name);
+            let lookup = banged_name(name);
             item.insert_snippet(cap, snippet).lookup_by(lookup);
         }
         _ if needs_bang => {
-            item.insert_text(banged_name(&escaped_name)).lookup_by(banged_name(&name));
+            item.insert_text(banged_name(&escaped_name)).lookup_by(banged_name(name));
         }
         _ => {
             cov_mark::hit!(dont_insert_macro_call_parens_unnecessary);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index 5675dfb5c6f..124abb17b6a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -31,13 +31,11 @@ pub(crate) fn render_struct_pat(
     }
 
     let name = local_name.unwrap_or_else(|| strukt.name(ctx.db()));
-    let (name, escaped_name) = (
-        name.unescaped().display(ctx.db()).to_smolstr(),
-        name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
-    );
+    let (name, escaped_name) =
+        (name.as_str(), name.display(ctx.db(), ctx.completion.edition).to_smolstr());
     let kind = strukt.kind(ctx.db());
-    let label = format_literal_label(name.as_str(), kind, ctx.snippet_cap());
-    let lookup = format_literal_lookup(name.as_str(), kind);
+    let label = format_literal_label(name, kind, ctx.snippet_cap());
+    let lookup = format_literal_lookup(name, kind);
     let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
 
     let db = ctx.db();
@@ -61,13 +59,13 @@ pub(crate) fn render_variant_pat(
 
     let (name, escaped_name) = match path {
         Some(path) => (
-            path.unescaped().display(ctx.db()).to_string().into(),
-            path.display(ctx.db(), ctx.completion.edition).to_string().into(),
+            path.display_verbatim(ctx.db()).to_smolstr(),
+            path.display(ctx.db(), ctx.completion.edition).to_smolstr(),
         ),
         None => {
             let name = local_name.unwrap_or_else(|| variant.name(ctx.db()));
             let it = (
-                name.unescaped().display(ctx.db()).to_smolstr(),
+                name.as_str().to_smolstr(),
                 name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
             );
             it
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
index 09eb19201c5..1b952f31360 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
@@ -32,14 +32,11 @@ fn render(
     let name = type_alias.name(db);
     let (name, escaped_name) = if with_eq {
         (
-            SmolStr::from_iter([&name.unescaped().display(db).to_smolstr(), " = "]),
+            SmolStr::from_iter([&name.as_str().to_smolstr(), " = "]),
             SmolStr::from_iter([&name.display_no_db(ctx.completion.edition).to_smolstr(), " = "]),
         )
     } else {
-        (
-            name.unescaped().display(db).to_smolstr(),
-            name.display_no_db(ctx.completion.edition).to_smolstr(),
-        )
+        (name.as_str().to_smolstr(), name.display_no_db(ctx.completion.edition).to_smolstr())
     };
     let detail = type_alias.display(db, ctx.completion.edition).to_string();
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
index e053e299d90..74203626521 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
@@ -23,12 +23,12 @@ pub(crate) fn render_union_literal(
 
     let (qualified_name, escaped_qualified_name) = match path {
         Some(p) => (
-            p.unescaped().display(ctx.db()).to_string(),
-            p.display(ctx.db(), ctx.completion.edition).to_string(),
+            p.display_verbatim(ctx.db()).to_smolstr(),
+            p.display(ctx.db(), ctx.completion.edition).to_smolstr(),
         ),
         None => (
-            name.unescaped().display(ctx.db()).to_string(),
-            name.display(ctx.db(), ctx.completion.edition).to_string(),
+            name.as_str().to_smolstr(),
+            name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
         ),
     };
     let label = format_literal_label(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
index 04bb178c658..866b83a6146 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
@@ -164,7 +164,7 @@ impl Snippet {
 }
 
 fn import_edits(ctx: &CompletionContext<'_>, requires: &[ModPath]) -> Option<Vec<LocatedImport>> {
-    let import_cfg = ctx.config.import_path_config();
+    let import_cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     let resolve = |import| {
         let item = ctx.scope.resolve_mod_path(import).next()?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index b7dbf0a6306..9d91f95eb65 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -87,6 +87,8 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig {
     fields_to_resolve: CompletionFieldsToResolve::empty(),
     exclude_flyimport: vec![],
     exclude_traits: &[],
+    enable_auto_await: true,
+    enable_auto_iter: true,
 };
 
 pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
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 e117dbf4bdf..663a038580d 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
@@ -1965,3 +1965,24 @@ fn bar() {
         "#]],
     );
 }
+
+#[test]
+fn doc_hidden_enum_variant() {
+    check(
+        r#"
+//- /foo.rs crate:foo
+pub enum Enum {
+    #[doc(hidden)] Hidden,
+    Visible,
+}
+
+//- /lib.rs crate:lib deps:foo
+fn foo() {
+    let _ = foo::Enum::$0;
+}
+    "#,
+        expect![[r#"
+            ev Visible Visible
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
index d491e438fef..2e7c53def7f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
@@ -1391,6 +1391,41 @@ pub struct FooStruct {}
 }
 
 #[test]
+fn flyimport_pattern_unstable_path() {
+    check(
+        r#"
+//- /main.rs crate:main deps:std
+fn function() {
+    let foo$0
+}
+//- /std.rs crate:std
+#[unstable]
+pub mod unstable {
+    pub struct FooStruct {}
+}
+"#,
+        expect![""],
+    );
+    check(
+        r#"
+//- toolchain:nightly
+//- /main.rs crate:main deps:std
+fn function() {
+    let foo$0
+}
+//- /std.rs crate:std
+#[unstable]
+pub mod unstable {
+    pub struct FooStruct {}
+}
+"#,
+        expect![[r#"
+            st FooStruct (use std::unstable::FooStruct)
+        "#]],
+    );
+}
+
+#[test]
 fn flyimport_pattern_unstable_item_on_nightly() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
index 04b3a47a64d..593b1edde5c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
@@ -451,3 +451,20 @@ marco_rules! m { () => {} }
         "#]],
     );
 }
+
+#[test]
+fn use_tree_doc_hidden() {
+    check(
+        r#"
+//- /foo.rs crate:foo
+#[doc(hidden)] pub struct Hidden;
+pub struct Visible;
+
+//- /lib.rs crate:lib deps:foo
+use foo::$0;
+    "#,
+        expect![[r#"
+            st Visible Visible
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index 49d26dfe25c..d12bda0816f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -794,7 +794,7 @@ impl NameRefClass {
                                 hir::AssocItem::TypeAlias(it) => Some(it),
                                 _ => None,
                             })
-                            .find(|alias| alias.name(sema.db).eq_ident(name_ref.text().as_str()))
+                            .find(|alias| alias.name(sema.db).as_str() == name_ref.text().trim_start_matches("r#"))
                         {
                             // No substitution, this can only occur in type position.
                             return Some(NameRefClass::Definition(Definition::TypeAlias(ty), None));
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
index 9e3506d6f53..2f4d07446f2 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
@@ -46,6 +46,10 @@ impl FamousDefs<'_, '_> {
         self.find_trait("core:cmp:Ord")
     }
 
+    pub fn core_convert_FromStr(&self) -> Option<Trait> {
+        self.find_trait("core:str:FromStr")
+    }
+
     pub fn core_convert_From(&self) -> Option<Trait> {
         self.find_trait("core:convert:From")
     }
@@ -54,6 +58,14 @@ impl FamousDefs<'_, '_> {
         self.find_trait("core:convert:Into")
     }
 
+    pub fn core_convert_TryFrom(&self) -> Option<Trait> {
+        self.find_trait("core:convert:TryFrom")
+    }
+
+    pub fn core_convert_TryInto(&self) -> Option<Trait> {
+        self.find_trait("core:convert:TryInto")
+    }
+
     pub fn core_convert_Index(&self) -> Option<Trait> {
         self.find_trait("core:ops:Index")
     }
@@ -130,6 +142,13 @@ impl FamousDefs<'_, '_> {
         self.find_macro("core:unimplemented")
     }
 
+    pub fn core_fmt_Display(&self) -> Option<Trait> {
+        self.find_trait("core:fmt:Display")
+    }
+
+    pub fn alloc_string_ToString(&self) -> Option<Trait> {
+        self.find_trait("alloc:string:ToString")
+    }
     pub fn builtin_crates(&self) -> impl Iterator<Item = Crate> {
         IntoIterator::into_iter([
             self.std(),
@@ -202,14 +221,15 @@ impl FamousDefs<'_, '_> {
         for segment in path {
             module = module.children(db).find_map(|child| {
                 let name = child.name(db)?;
-                if name.eq_ident(segment) {
+                if name.as_str() == segment {
                     Some(child)
                 } else {
                     None
                 }
             })?;
         }
-        let def = module.scope(db, None).into_iter().find(|(name, _def)| name.eq_ident(trait_))?.1;
+        let def =
+            module.scope(db, None).into_iter().find(|(name, _def)| name.as_str() == trait_)?.1;
         Some(def)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index a045c22c2df..f045e44dd31 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -319,6 +319,7 @@ impl Ctx<'_> {
                                 prefer_no_std: false,
                                 prefer_prelude: true,
                                 prefer_absolute: false,
+                                allow_unstable: true,
                             };
                             let found_path = self.target_module.find_path(
                                 self.source_scope.db.upcast(),
@@ -378,6 +379,7 @@ impl Ctx<'_> {
                     prefer_no_std: false,
                     prefer_prelude: true,
                     prefer_absolute: false,
+                    allow_unstable: true,
                 };
                 let found_path =
                     self.target_module.find_path(self.source_scope.db.upcast(), def, cfg)?;
@@ -417,6 +419,7 @@ impl Ctx<'_> {
                             prefer_no_std: false,
                             prefer_prelude: true,
                             prefer_absolute: false,
+                            allow_unstable: true,
                         };
                         let found_path = self.target_module.find_path(
                             self.source_scope.db.upcast(),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index 42efbd68e33..59914bedde4 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -263,13 +263,12 @@ fn rename_mod(
         //  - Module has submodules defined in separate files
         let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) {
             // Go up one level since the anchor is inside the dir we're trying to rename
-            (true, _, Some(mod_name)) => Some((
-                format!("../{}", mod_name.unescaped().display(sema.db)),
-                format!("../{new_name}"),
-            )),
+            (true, _, Some(mod_name)) => {
+                Some((format!("../{}", mod_name.as_str()), format!("../{new_name}")))
+            }
             // The anchor is on the same level as target dir
             (false, true, Some(mod_name)) => {
-                Some((mod_name.unescaped().display(sema.db).to_string(), new_name.to_owned()))
+                Some((mod_name.as_str().to_owned(), new_name.to_owned()))
             }
             _ => None,
         };
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index a75aba137be..7fc563a4241 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -625,7 +625,7 @@ impl<'a> FindUsages<'a> {
             let _p = tracing::info_span!("collect_possible_aliases").entered();
 
             let db = sema.db;
-            let container_name = container.name(db).unescaped().display(db).to_smolstr();
+            let container_name = container.name(db).as_str().to_smolstr();
             let search_scope = Definition::from(container).search_scope(db);
             let mut seen = FxHashSet::default();
             let mut completed = FxHashSet::default();
@@ -925,12 +925,8 @@ impl<'a> FindUsages<'a> {
                             .or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
                     })
                 };
-                // We need to unescape the name in case it is written without "r#" in earlier
-                // editions of Rust where it isn't a keyword.
-                self.def
-                    .name(sema.db)
-                    .or_else(self_kw_refs)
-                    .map(|it| it.unescaped().display(sema.db).to_smolstr())
+                // We need to search without the `r#`, hence `as_str` access.
+                self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.as_str().to_smolstr())
             }
         };
         let name = match &name {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index c94644eeb89..e5ce10a771e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -143,7 +143,7 @@ fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Ar
 fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc<SymbolIndex> {
     let _p = tracing::info_span!("module_symbols").entered();
 
-    Arc::new(SymbolIndex::new(SymbolCollector::collect_module(db.upcast(), module)))
+    Arc::new(SymbolIndex::new(SymbolCollector::new_module(db.upcast(), module)))
 }
 
 pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc<SymbolIndex>]> {
@@ -284,13 +284,15 @@ impl SymbolIndex {
             builder.insert(key, value).unwrap();
         }
 
-        // FIXME: fst::Map should ideally have a way to shrink the backing buffer without the unwrap dance
-        let map = fst::Map::new({
-            let mut buf = builder.into_inner().unwrap();
-            buf.shrink_to_fit();
-            buf
-        })
-        .unwrap();
+        let map = builder
+            .into_inner()
+            .and_then(|mut buf| {
+                fst::Map::new({
+                    buf.shrink_to_fit();
+                    buf
+                })
+            })
+            .unwrap();
         SymbolIndex { symbols, map }
     }
 
@@ -491,7 +493,7 @@ pub(self) use crate::Trait as IsThisJustATrait;
             .modules(&db)
             .into_iter()
             .map(|module_id| {
-                let mut symbols = SymbolCollector::collect_module(&db, module_id);
+                let mut symbols = SymbolCollector::new_module(&db, module_id);
                 symbols.sort_by_key(|it| it.name.as_str().to_owned());
                 (module_id, symbols)
             })
@@ -518,7 +520,7 @@ struct Duplicate;
             .modules(&db)
             .into_iter()
             .map(|module_id| {
-                let mut symbols = SymbolCollector::collect_module(&db, module_id);
+                let mut symbols = SymbolCollector::new_module(&db, module_id);
                 symbols.sort_by_key(|it| it.name.as_str().to_owned());
                 (module_id, symbols)
             })
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 557c95f704b..0a7141c19b6 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -31,6 +31,12 @@ const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"];
 /// `Result<User, Error>` -> `User`
 const WRAPPER_TYPES: &[&str] = &["Box", "Arc", "Rc", "Option", "Result"];
 
+/// Generic types replaced by a plural of their first argument.
+///
+/// # Examples
+/// `Vec<Name>` -> "names"
+const SEQUENCE_TYPES: &[&str] = &["Vec", "VecDeque", "LinkedList"];
+
 /// Prefixes to strip from methods names
 ///
 /// # Examples
@@ -378,6 +384,11 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
             return name_of_type(&inner_ty, db, edition);
         }
 
+        if SEQUENCE_TYPES.contains(&name.as_str()) {
+            let inner_ty = ty.type_arguments().next();
+            return Some(sequence_name(inner_ty.as_ref(), db, edition));
+        }
+
         name
     } else if let Some(trait_) = ty.as_dyn_trait() {
         trait_name(&trait_, db, edition)?
@@ -390,12 +401,32 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
         name
     } else if let Some(inner_ty) = ty.remove_ref() {
         return name_of_type(&inner_ty, db, edition);
+    } else if let Some(inner_ty) = ty.as_slice() {
+        return Some(sequence_name(Some(&inner_ty), db, edition));
     } else {
         return None;
     };
     normalize(&name)
 }
 
+fn sequence_name(inner_ty: Option<&hir::Type>, db: &RootDatabase, edition: Edition) -> SmolStr {
+    let items_str = SmolStr::new_static("items");
+    let Some(inner_ty) = inner_ty else {
+        return items_str;
+    };
+    let Some(name) = name_of_type(inner_ty, db, edition) else {
+        return items_str;
+    };
+
+    if name.ends_with(['s', 'x', 'y']) {
+        // Given a type called e.g. "Boss", "Fox" or "Story", don't try to
+        // create a plural.
+        items_str
+    } else {
+        SmolStr::new(format!("{name}s"))
+    }
+}
+
 fn trait_name(trait_: &hir::Trait, db: &RootDatabase, edition: Edition) -> Option<String> {
     let name = trait_.name(db).display(db, edition).to_string();
     if USELESS_TRAITS.contains(&name.as_str()) {
@@ -898,6 +929,58 @@ fn foo() { $0(bar())$0; }
     }
 
     #[test]
+    fn vec_value() {
+        check(
+            r#"
+struct Vec<T> {};
+struct Seed;
+fn bar() -> Vec<Seed> {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seeds",
+        );
+    }
+
+    #[test]
+    fn vec_value_ends_with_s() {
+        check(
+            r#"
+struct Vec<T> {};
+struct Boss;
+fn bar() -> Vec<Boss> {}
+fn foo() { $0(bar())$0; }
+"#,
+            "items",
+        );
+    }
+
+    #[test]
+    fn vecdeque_value() {
+        check(
+            r#"
+struct VecDeque<T> {};
+struct Seed;
+fn bar() -> VecDeque<Seed> {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seeds",
+        );
+    }
+
+    #[test]
+    fn slice_value() {
+        check(
+            r#"
+struct Vec<T> {};
+struct Seed;
+fn bar() -> &[Seed] {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seeds",
+        );
+    }
+
+    #[test]
     fn ref_call() {
         check(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 535777dfcbe..7dce95592b8 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -1007,6 +1007,39 @@
                 is_alias: false,
                 is_assoc: false,
             },
+            FileSymbol {
+                name: "ThisStruct",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                4,
+                            ),
+                        },
+                    ),
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: EditionedFileId(
+                        FileId(
+                            1,
+                        ),
+                        Edition2021,
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: USE_TREE,
+                        range: 85..125,
+                    },
+                    name_ptr: AstPtr(
+                        SyntaxNodePtr {
+                            kind: NAME,
+                            range: 115..125,
+                        },
+                    ),
+                },
+                container_name: None,
+                is_alias: false,
+                is_assoc: false,
+            },
         ],
     ),
 ]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
index 515bc418cb4..2fdd8358637 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
@@ -26,7 +26,7 @@ impl TryEnum {
             _ => return None,
         };
         TryEnum::ALL.iter().find_map(|&var| {
-            if enum_.name(sema.db).eq_ident(var.type_name()) {
+            if enum_.name(sema.db).as_str() == var.type_name() {
                 return Some(var);
             }
             None
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index dca889d1a8e..f22041ebe23 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -147,6 +147,7 @@ pub(crate) fn json_in_items(
                             prefer_no_std: config.prefer_no_std,
                             prefer_prelude: config.prefer_prelude,
                             prefer_absolute: config.prefer_absolute,
+                            allow_unstable: true,
                         };
 
                         if !scope_has("Serialize") {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index fd1044e51bc..938b7182bc9 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -128,6 +128,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                                 prefer_no_std: ctx.config.prefer_no_std,
                                 prefer_prelude: ctx.config.prefer_prelude,
                                 prefer_absolute: ctx.config.prefer_absolute,
+                                allow_unstable: ctx.is_nightly,
                             },
                         )?;
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 3ad84f7bda2..b023a95fb35 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -70,6 +70,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
                     prefer_no_std: ctx.config.prefer_no_std,
                     prefer_prelude: ctx.config.prefer_prelude,
                     prefer_absolute: ctx.config.prefer_absolute,
+                    allow_unstable: ctx.is_nightly,
                 },
                 ctx.edition,
             )
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 13591dfb2ee..f3109b9bb73 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
@@ -112,7 +112,7 @@ fn fixes(
                 // shouldn't occur
                 _ => continue 'crates,
             };
-            match current.children.iter().find(|(name, _)| name.eq_ident(seg)) {
+            match current.children.iter().find(|(name, _)| name.as_str() == seg) {
                 Some((_, &child)) => current = &crate_def_map[child],
                 None => continue 'crates,
             }
@@ -161,7 +161,7 @@ fn fixes(
             // try finding a parent that has an inline tree from here on
             let mut current = module;
             for s in stack.iter().rev() {
-                match module.children.iter().find(|(name, _)| name.eq_ident(s)) {
+                match module.children.iter().find(|(name, _)| name.as_str() == s) {
                     Some((_, child)) => {
                         current = &crate_def_map[*child];
                     }
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 1e99d7ad6e6..50c91a69602 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -83,7 +83,7 @@ use either::Either;
 use hir::{db::ExpandDatabase, diagnostics::AnyDiagnostic, Crate, HirFileId, InFile, Semantics};
 use ide_db::{
     assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
-    base_db::SourceDatabase,
+    base_db::{ReleaseChannel, SourceDatabase},
     generated::lints::{Lint, LintGroup, CLIPPY_LINT_GROUPS, DEFAULT_LINTS, DEFAULT_LINT_GROUPS},
     imports::insert_use::InsertUseConfig,
     label::Label,
@@ -276,6 +276,7 @@ struct DiagnosticsContext<'a> {
     sema: Semantics<'a, RootDatabase>,
     resolve: &'a AssistResolveStrategy,
     edition: Edition,
+    is_nightly: bool,
 }
 
 impl DiagnosticsContext<'_> {
@@ -368,7 +369,11 @@ pub fn semantic_diagnostics(
 
     let module = sema.file_to_module_def(file_id);
 
-    let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition() };
+    let is_nightly = matches!(
+        module.and_then(|m| db.toolchain_channel(m.krate().into())),
+        Some(ReleaseChannel::Nightly) | None
+    );
+    let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition(), is_nightly };
 
     let mut diags = Vec::new();
     match module {
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index 4edc3633fbe..4bead14e31d 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -673,6 +673,7 @@ impl Match {
                     prefer_no_std: false,
                     prefer_prelude: true,
                     prefer_absolute: false,
+                    allow_unstable: true,
                 };
                 let mod_path = module.find_path(sema.db, module_def, cfg).ok_or_else(|| {
                     match_error!("Failed to render template path `{}` at match location")
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 bc9843f3f35..cfd8919730a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -413,8 +413,7 @@ fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option<
 fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option<String> {
     def.canonical_module_path(db).map(|it| {
         let mut path = String::new();
-        it.flat_map(|it| it.name(db))
-            .for_each(|name| format_to!(path, "{}/", name.unescaped().display(db)));
+        it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name.as_str()));
         path
     })
 }
@@ -590,10 +589,10 @@ fn filename_and_frag_for_def(
     let res = match def {
         Definition::Adt(adt) => match adt {
             Adt::Struct(s) => {
-                format!("struct.{}.html", s.name(db).unescaped().display(db.upcast()))
+                format!("struct.{}.html", s.name(db).as_str())
             }
-            Adt::Enum(e) => format!("enum.{}.html", e.name(db).unescaped().display(db.upcast())),
-            Adt::Union(u) => format!("union.{}.html", u.name(db).unescaped().display(db.upcast())),
+            Adt::Enum(e) => format!("enum.{}.html", e.name(db).as_str()),
+            Adt::Union(u) => format!("union.{}.html", u.name(db).as_str()),
         },
         Definition::Crate(_) => String::from("index.html"),
         Definition::Module(m) => match m.name(db) {
@@ -603,48 +602,48 @@ fn filename_and_frag_for_def(
                     Some(kw) => {
                         format!("keyword.{}.html", kw)
                     }
-                    None => format!("{}/index.html", name.unescaped().display(db.upcast())),
+                    None => format!("{}/index.html", name.as_str()),
                 }
             }
             None => String::from("index.html"),
         },
         Definition::Trait(t) => {
-            format!("trait.{}.html", t.name(db).unescaped().display(db.upcast()))
+            format!("trait.{}.html", t.name(db).as_str())
         }
         Definition::TraitAlias(t) => {
-            format!("traitalias.{}.html", t.name(db).unescaped().display(db.upcast()))
+            format!("traitalias.{}.html", t.name(db).as_str())
         }
         Definition::TypeAlias(t) => {
-            format!("type.{}.html", t.name(db).unescaped().display(db.upcast()))
+            format!("type.{}.html", t.name(db).as_str())
         }
         Definition::BuiltinType(t) => {
-            format!("primitive.{}.html", t.name().unescaped().display(db.upcast()))
+            format!("primitive.{}.html", t.name().as_str())
         }
         Definition::Function(f) => {
-            format!("fn.{}.html", f.name(db).unescaped().display(db.upcast()))
+            format!("fn.{}.html", f.name(db).as_str())
         }
         Definition::Variant(ev) => {
             format!(
                 "enum.{}.html#variant.{}",
-                ev.parent_enum(db).name(db).unescaped().display(db.upcast()),
-                ev.name(db).unescaped().display(db.upcast())
+                ev.parent_enum(db).name(db).as_str(),
+                ev.name(db).as_str()
             )
         }
         Definition::Const(c) => {
-            format!("const.{}.html", c.name(db)?.unescaped().display(db.upcast()))
+            format!("const.{}.html", c.name(db)?.as_str())
         }
         Definition::Static(s) => {
-            format!("static.{}.html", s.name(db).unescaped().display(db.upcast()))
+            format!("static.{}.html", s.name(db).as_str())
         }
         Definition::Macro(mac) => match mac.kind(db) {
             hir::MacroKind::Declarative
             | hir::MacroKind::BuiltIn
             | hir::MacroKind::Attr
             | hir::MacroKind::ProcMacro => {
-                format!("macro.{}.html", mac.name(db).unescaped().display(db.upcast()))
+                format!("macro.{}.html", mac.name(db).as_str())
             }
             hir::MacroKind::Derive => {
-                format!("derive.{}.html", mac.name(db).unescaped().display(db.upcast()))
+                format!("derive.{}.html", mac.name(db).as_str())
             }
         },
         Definition::Field(field) => {
@@ -654,11 +653,7 @@ fn filename_and_frag_for_def(
                 hir::VariantDef::Variant(it) => Definition::Variant(it),
             };
             let (_, file, _) = filename_and_frag_for_def(db, def)?;
-            return Some((
-                def,
-                file,
-                Some(format!("structfield.{}", field.name(db).unescaped().display(db.upcast()))),
-            ));
+            return Some((def, file, Some(format!("structfield.{}", field.name(db).as_str()))));
         }
         Definition::SelfType(impl_) => {
             let adt = impl_.self_ty(db).as_adt()?.into();
@@ -667,7 +662,7 @@ fn filename_and_frag_for_def(
             return Some((adt, file, Some(String::from("impl"))));
         }
         Definition::ExternCrateDecl(it) => {
-            format!("{}/index.html", it.name(db).unescaped().display(db.upcast()))
+            format!("{}/index.html", it.name(db).as_str())
         }
         Definition::Local(_)
         | Definition::GenericParam(_)
@@ -699,16 +694,16 @@ fn get_assoc_item_fragment(db: &dyn HirDatabase, assoc_item: hir::AssocItem) ->
             // Rustdoc makes this decision based on whether a method 'has defaultness'.
             // Currently this is only the case for provided trait methods.
             if is_trait_method && !function.has_body(db) {
-                format!("tymethod.{}", function.name(db).unescaped().display(db.upcast()))
+                format!("tymethod.{}", function.name(db).as_str())
             } else {
-                format!("method.{}", function.name(db).unescaped().display(db.upcast()))
+                format!("method.{}", function.name(db).as_str())
             }
         }
         AssocItem::Const(constant) => {
-            format!("associatedconstant.{}", constant.name(db)?.unescaped().display(db.upcast()))
+            format!("associatedconstant.{}", constant.name(db)?.as_str())
         }
         AssocItem::TypeAlias(ty) => {
-            format!("associatedtype.{}", ty.name(db).unescaped().display(db.upcast()))
+            format!("associatedtype.{}", ty.name(db).as_str())
         }
     })
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index f804cc36772..d18732a6b84 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -5,10 +5,14 @@ use crate::{
     navigation_target::{self, ToNav},
     FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
 };
-use hir::{AsAssocItem, AssocItem, FileRange, InFile, MacroFileIdExt, ModuleDef, Semantics};
+use hir::{
+    sym, AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, MacroFileIdExt,
+    ModuleDef, Semantics,
+};
 use ide_db::{
     base_db::{AnchoredPath, FileLoader, SourceDatabase},
     defs::{Definition, IdentClass},
+    famous_defs::FamousDefs,
     helpers::pick_best_token,
     RootDatabase, SymbolKind,
 };
@@ -129,15 +133,74 @@ pub(crate) fn goto_definition(
     Some(RangeInfo::new(original_token.text_range(), navs))
 }
 
-// If the token is into(), try_into(), parse(), search the definition of From, TryFrom, FromStr.
+// If the token is into(), try_into(), search the definition of From, TryFrom.
 fn find_definition_for_known_blanket_dual_impls(
     sema: &Semantics<'_, RootDatabase>,
     original_token: &SyntaxToken,
 ) -> Option<Vec<NavigationTarget>> {
     let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;
-    let target_method = sema.resolve_known_blanket_dual_impls(&method_call)?;
+    let callable = sema.resolve_method_call_as_callable(&method_call)?;
+    let CallableKind::Function(f) = callable.kind() else { return None };
+    let assoc = f.as_assoc_item(sema.db)?;
+
+    let return_type = callable.return_type();
+    let fd = FamousDefs(sema, return_type.krate(sema.db));
+
+    let t = match assoc.container(sema.db) {
+        hir::AssocItemContainer::Trait(t) => t,
+        hir::AssocItemContainer::Impl(impl_)
+            if impl_.self_ty(sema.db).is_str() && f.name(sema.db) == sym::parse =>
+        {
+            let t = fd.core_convert_FromStr()?;
+            let t_f = t.function(sema.db, &sym::from_str)?;
+            return sema
+                .resolve_trait_impl_method(
+                    return_type.clone(),
+                    t,
+                    t_f,
+                    [return_type.type_arguments().next()?],
+                )
+                .map(|f| def_to_nav(sema.db, f.into()));
+        }
+        hir::AssocItemContainer::Impl(_) => return None,
+    };
 
-    let def = Definition::from(target_method);
+    let fn_name = f.name(sema.db);
+    let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {
+        let dual = fd.core_convert_From()?;
+        let dual_f = dual.function(sema.db, &sym::from)?;
+        sema.resolve_trait_impl_method(
+            return_type.clone(),
+            dual,
+            dual_f,
+            [return_type, callable.receiver_param(sema.db)?.1],
+        )?
+    } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {
+        let dual = fd.core_convert_TryFrom()?;
+        let dual_f = dual.function(sema.db, &sym::try_from)?;
+        sema.resolve_trait_impl_method(
+            return_type.clone(),
+            dual,
+            dual_f,
+            // Extract the `T` from `Result<T, ..>`
+            [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],
+        )?
+    } else if fn_name == sym::to_string && fd.alloc_string_ToString() == Some(t) {
+        let dual = fd.core_fmt_Display()?;
+        let dual_f = dual.function(sema.db, &sym::fmt)?;
+        sema.resolve_trait_impl_method(
+            return_type.clone(),
+            dual,
+            dual_f,
+            [callable.receiver_param(sema.db)?.1.strip_reference()],
+        )?
+    } else {
+        return None;
+    };
+    // Assert that we got a trait impl function, if we are back in a trait definition we didn't
+    // succeed
+    let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;
+    let def = Definition::from(f);
     Some(def_to_nav(sema.db, def))
 }
 
@@ -3168,20 +3231,47 @@ fn f() {
             r#"
 //- minicore: from, str
 struct A;
-
 impl FromStr for A {
     type Error = String;
-
     fn from_str(value: &str) -> Result<Self, Self::Error> {
      //^^^^^^^^
         Ok(A)
     }
 }
-
 fn f() {
     let a: Result<A, _> = "aaaaaa".parse$0();
 }
         "#,
         );
     }
+
+    #[test]
+    fn to_string_call_to_display_definition() {
+        check(
+            r#"
+//- minicore:fmt
+//- /alloc.rs crate:alloc
+pub mod string {
+    pub struct String;
+    pub trait ToString {
+        fn to_string(&self) -> String;
+    }
+
+    impl<T: core::fmt::Display> ToString for T {
+        fn to_string(&self) -> String { String }
+    }
+}
+//- /lib.rs crate:lib deps:alloc
+use alloc::string::ToString;
+struct A;
+impl core::fmt::Display for A {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {}
+    // ^^^
+}
+fn f() {
+    A.to_string$0();
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 18a3fed07ec..9d4c103fc2e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -346,7 +346,7 @@ fn hover_offset(
         .unique()
         .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
             acc.actions.extend(actions);
-            acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
+            acc.markup = Markup::from(format!("{}\n\n---\n{markup}", acc.markup));
             acc
         })
         .map(|mut res: HoverResult| {
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 46242b75dd0..40f3406b72d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -1082,7 +1082,19 @@ fn render_memory_layout(
 
     if config.niches {
         if let Some(niches) = layout.niches() {
-            format_to!(label, "niches = {niches}, ");
+            if niches > 1024 {
+                if niches.is_power_of_two() {
+                    format_to!(label, "niches = 2{}, ", pwr2_to_exponent(niches));
+                } else if is_pwr2plus1(niches) {
+                    format_to!(label, "niches = 2{} + 1, ", pwr2_to_exponent(niches - 1));
+                } else if is_pwr2minus1(niches) {
+                    format_to!(label, "niches = 2{} - 1, ", pwr2_to_exponent(niches + 1));
+                } else {
+                    format_to!(label, "niches = a lot, ");
+                }
+            } else {
+                format_to!(label, "niches = {niches}, ");
+            }
         }
     }
     label.pop(); // ' '
@@ -1210,3 +1222,74 @@ fn render_dyn_compatibility(
         }
     }
 }
+
+fn is_pwr2minus1(val: u128) -> bool {
+    val == u128::MAX || (val + 1).is_power_of_two()
+}
+
+fn is_pwr2plus1(val: u128) -> bool {
+    val != 0 && (val - 1).is_power_of_two()
+}
+
+/// Formats a power of two as an exponent of two, i.e. 16 => ⁴. Note that `num` MUST be a power
+/// of 2, or this function will panic.
+fn pwr2_to_exponent(num: u128) -> String {
+    const DIGITS: [char; 10] = ['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'];
+    assert_eq!(num.count_ones(), 1);
+    num.trailing_zeros()
+        .to_string()
+        .chars()
+        .map(|c| c.to_digit(10).unwrap() as usize)
+        .map(|idx| DIGITS[idx])
+        .collect::<String>()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    const TESTERS: [u128; 10] = [0, 1, 2, 3, 4, 255, 256, 257, u128::MAX - 1, u128::MAX];
+
+    #[test]
+    fn test_is_pwr2minus1() {
+        const OUTCOMES: [bool; 10] =
+            [true, true, false, true, false, true, false, false, false, true];
+        for (test, expected) in TESTERS.iter().zip(OUTCOMES) {
+            let actual = is_pwr2minus1(*test);
+            assert_eq!(actual, expected, "is_pwr2minu1({test}) gave {actual}, expected {expected}");
+        }
+    }
+
+    #[test]
+    fn test_is_pwr2plus1() {
+        const OUTCOMES: [bool; 10] =
+            [false, false, true, true, false, false, false, true, false, false];
+        for (test, expected) in TESTERS.iter().zip(OUTCOMES) {
+            let actual = is_pwr2plus1(*test);
+            assert_eq!(actual, expected, "is_pwr2plus1({test}) gave {actual}, expected {expected}");
+        }
+    }
+
+    #[test]
+    fn test_pwr2_to_exponent() {
+        const TESTERS: [u128; 9] = [
+            1,
+            2,
+            4,
+            8,
+            16,
+            9223372036854775808,
+            18446744073709551616,
+            36893488147419103232,
+            170141183460469231731687303715884105728,
+        ];
+        const OUTCOMES: [&str; 9] = ["⁰", "¹", "²", "³", "⁴", "⁶³", "⁶⁴", "⁶⁵", "¹²⁷"];
+        for (test, expected) in TESTERS.iter().zip(OUTCOMES) {
+            let actual = pwr2_to_exponent(*test);
+            assert_eq!(
+                actual, expected,
+                "pwr2_to_exponent({test}) returned {actual}, expected {expected}",
+            );
+        }
+    }
+}
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 014b751f95b..8c32cc9720a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -303,6 +303,7 @@ m!(ab$0c);
             ---
 
             Outer
+
             ---
 
             ```rust
@@ -1357,7 +1358,7 @@ fn hover_enum_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4, niches = 4294967288
+            size = 12 (0xC), align = 4, niches = a lot
         "#]],
     );
 }
@@ -4401,6 +4402,7 @@ fn main() {
             ---
 
             size = 8, align = 8, niches = 1
+
             ---
 
             ```rust
@@ -10094,6 +10096,7 @@ fn bar() {
             ```rust
             let field: i32
             ```
+
             ---
 
             ```rust
@@ -10128,6 +10131,7 @@ fn bar() {
             ---
 
             size = 4, align = 4
+
             ---
 
             ```rust
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 6d83a747d76..1f723c85df7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -209,7 +209,7 @@ fn hints(
 ) {
     closing_brace::hints(hints, sema, config, file_id, node.clone());
     if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
-        generic_param::hints(hints, sema, config, any_has_generic_args);
+        generic_param::hints(hints, famous_defs, config, any_has_generic_args);
     }
 
     match_ast! {
@@ -300,22 +300,23 @@ pub struct InlayHintsConfig {
     pub closing_brace_hints_min_lines: Option<usize>,
     pub fields_to_resolve: InlayFieldsToResolve,
 }
+
 impl InlayHintsConfig {
-    fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> Lazy<TextEdit> {
+    fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> {
         if self.fields_to_resolve.resolve_text_edits {
-            Lazy::Lazy
+            LazyProperty::Lazy
         } else {
             let edit = finish();
             never!(edit.is_empty(), "inlay hint produced an empty text edit");
-            Lazy::Computed(edit)
+            LazyProperty::Computed(edit)
         }
     }
 
-    fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> Lazy<InlayTooltip> {
+    fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> LazyProperty<InlayTooltip> {
         if self.fields_to_resolve.resolve_hint_tooltip
             && self.fields_to_resolve.resolve_label_tooltip
         {
-            Lazy::Lazy
+            LazyProperty::Lazy
         } else {
             let tooltip = finish();
             never!(
@@ -326,7 +327,20 @@ impl InlayHintsConfig {
                 .is_empty(),
                 "inlay hint produced an empty tooltip"
             );
-            Lazy::Computed(tooltip)
+            LazyProperty::Computed(tooltip)
+        }
+    }
+
+    /// This always reports a resolvable location, so only use this when it is very likely for a
+    /// location link to actually resolve but where computing `finish` would be costly.
+    fn lazy_location_opt(
+        &self,
+        finish: impl FnOnce() -> Option<FileRange>,
+    ) -> Option<LazyProperty<FileRange>> {
+        if self.fields_to_resolve.resolve_label_location {
+            Some(LazyProperty::Lazy)
+        } else {
+            finish().map(LazyProperty::Computed)
         }
     }
 }
@@ -441,7 +455,7 @@ pub struct InlayHint {
     /// The actual label to show in the inlay hint.
     pub label: InlayHintLabel,
     /// Text edit to apply when "accepting" this inlay hint.
-    pub text_edit: Option<Lazy<TextEdit>>,
+    pub text_edit: Option<LazyProperty<TextEdit>>,
     /// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
     /// hint does not support resolving.
     pub resolve_parent: Option<TextRange>,
@@ -449,15 +463,15 @@ pub struct InlayHint {
 
 /// A type signaling that a value is either computed, or is available for computation.
 #[derive(Clone, Debug)]
-pub enum Lazy<T> {
+pub enum LazyProperty<T> {
     Computed(T),
     Lazy,
 }
 
-impl<T> Lazy<T> {
+impl<T> LazyProperty<T> {
     pub fn computed(self) -> Option<T> {
         match self {
-            Lazy::Computed(it) => Some(it),
+            LazyProperty::Computed(it) => Some(it),
             _ => None,
         }
     }
@@ -508,8 +522,8 @@ pub struct InlayHintLabel {
 impl InlayHintLabel {
     pub fn simple(
         s: impl Into<String>,
-        tooltip: Option<Lazy<InlayTooltip>>,
-        linked_location: Option<FileRange>,
+        tooltip: Option<LazyProperty<InlayTooltip>>,
+        linked_location: Option<LazyProperty<FileRange>>,
     ) -> InlayHintLabel {
         InlayHintLabel {
             parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location, tooltip }],
@@ -593,16 +607,16 @@ pub struct InlayHintLabelPart {
     /// refers to (not necessarily the location itself).
     /// When setting this, no tooltip must be set on the containing hint, or VS Code will display
     /// them both.
-    pub linked_location: Option<FileRange>,
+    pub linked_location: Option<LazyProperty<FileRange>>,
     /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like
     /// hover requests to show.
-    pub tooltip: Option<Lazy<InlayTooltip>>,
+    pub tooltip: Option<LazyProperty<InlayTooltip>>,
 }
 
 impl std::hash::Hash for InlayHintLabelPart {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
         self.text.hash(state);
-        self.linked_location.hash(state);
+        self.linked_location.is_some().hash(state);
         self.tooltip.is_some().hash(state);
     }
 }
@@ -610,7 +624,9 @@ impl std::hash::Hash for InlayHintLabelPart {
 impl fmt::Debug for InlayHintLabelPart {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Self { text, linked_location: None, tooltip: None | Some(Lazy::Lazy) } => text.fmt(f),
+            Self { text, linked_location: None, tooltip: None | Some(LazyProperty::Lazy) } => {
+                text.fmt(f)
+            }
             Self { text, linked_location, tooltip } => f
                 .debug_struct("InlayHintLabelPart")
                 .field("text", text)
@@ -618,8 +634,10 @@ impl fmt::Debug for InlayHintLabelPart {
                 .field(
                     "tooltip",
                     &tooltip.as_ref().map_or("", |it| match it {
-                        Lazy::Computed(InlayTooltip::String(it) | InlayTooltip::Markdown(it)) => it,
-                        Lazy::Lazy => "",
+                        LazyProperty::Computed(
+                            InlayTooltip::String(it) | InlayTooltip::Markdown(it),
+                        ) => it,
+                        LazyProperty::Lazy => "",
                     }),
                 )
                 .finish(),
@@ -632,7 +650,8 @@ struct InlayHintLabelBuilder<'a> {
     db: &'a RootDatabase,
     result: InlayHintLabel,
     last_part: String,
-    location: Option<FileRange>,
+    resolve: bool,
+    location: Option<LazyProperty<FileRange>>,
 }
 
 impl fmt::Write for InlayHintLabelBuilder<'_> {
@@ -645,11 +664,16 @@ impl HirWrite for InlayHintLabelBuilder<'_> {
     fn start_location_link(&mut self, def: ModuleDefId) {
         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();
-        let location =
-            FileRange { file_id: location.file_id, range: location.focus_or_full_range() };
-        self.location = Some(location);
+
+        self.location = Some(if self.resolve {
+            LazyProperty::Lazy
+        } else {
+            LazyProperty::Computed({
+                let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
+                let location = location.call_site();
+                FileRange { file_id: location.file_id, range: location.focus_or_full_range() }
+            })
+        });
     }
 
     fn end_location_link(&mut self) {
@@ -735,6 +759,7 @@ fn label_of_ty(
         last_part: String::new(),
         location: None,
         result: InlayHintLabel::default(),
+        resolve: config.fields_to_resolve.resolve_label_location,
     };
     let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config, edition);
     let r = label_builder.finish();
@@ -783,7 +808,7 @@ fn ty_to_text_edit(
     ty: &hir::Type,
     offset_to_insert: TextSize,
     prefix: impl Into<String>,
-) -> Option<Lazy<TextEdit>> {
+) -> Option<LazyProperty<TextEdit>> {
     // FIXME: Limit the length and bail out on excess somehow?
     let rendered = sema
         .scope(node_for_hint)
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 ab5464156f0..01a1a4545c4 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
@@ -1206,4 +1206,38 @@ fn f5<G: T<Assoc = ()>>(it: G) {
 "#,
         );
     }
+
+    #[test]
+    fn regression_19007() {
+        check_types(
+            r#"
+trait Foo {
+    type Assoc;
+
+    fn foo(&self) -> Self::Assoc;
+}
+
+trait Bar {
+    type Target;
+}
+
+trait Baz<T> {}
+
+struct Struct<T: Foo> {
+    field: T,
+}
+
+impl<T> Struct<T>
+where
+    T: Foo,
+    T::Assoc: Baz<<T::Assoc as Bar>::Target> + Bar,
+{
+    fn f(&self) {
+        let x = self.field.foo();
+          //^ impl Baz<<<T as Foo>::Assoc as Bar>::Target> + Bar
+    }
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
index 429ddd31cbd..e9b728bcaa7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
@@ -22,11 +22,7 @@ pub(super) fn hints(
         return None;
     }
 
-    let linked_location =
-        famous_defs.core_marker_Sized().and_then(|it| it.try_to_nav(sema.db)).map(|it| {
-            let n = it.call_site();
-            FileRange { file_id: n.file_id, range: n.focus_or_full_range() }
-        });
+    let sized_trait = famous_defs.core_marker_Sized();
 
     for param in params.type_or_const_params() {
         match param {
@@ -48,7 +44,17 @@ pub(super) fn hints(
                         }
                         hint.parts.push(InlayHintLabelPart {
                             text: "Sized".to_owned(),
-                            linked_location,
+                            linked_location: sized_trait.and_then(|it| {
+                                config.lazy_location_opt(|| {
+                                    it.try_to_nav(sema.db).map(|it| {
+                                        let n = it.call_site();
+                                        FileRange {
+                                            file_id: n.file_id,
+                                            range: n.focus_or_full_range(),
+                                        }
+                                    })
+                                })
+                            }),
                             tooltip: None,
                         });
                         if has_bounds {
@@ -134,12 +140,14 @@ fn foo<T>() {}
                             InlayHintLabelPart {
                                 text: "Sized",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 135..140,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 135..140,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
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 7fa7ab1a94d..8471547727f 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
@@ -81,7 +81,10 @@ mod tests {
 
     use crate::{
         fixture,
-        inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG},
+        inlay_hints::{
+            tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG},
+            LazyProperty,
+        },
         InlayHintsConfig,
     };
 
@@ -99,7 +102,7 @@ mod tests {
         let (analysis, file_id) = fixture::file(ra_fixture);
         let mut inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
         inlay_hints.iter_mut().flat_map(|hint| &mut hint.label.parts).for_each(|hint| {
-            if let Some(loc) = &mut hint.linked_location {
+            if let Some(LazyProperty::Computed(loc)) = &mut hint.linked_location {
                 loc.range = TextRange::empty(TextSize::from(0));
             }
         });
@@ -134,12 +137,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "B",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 63..64,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 63..64,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -151,12 +156,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "A",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..8,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..8,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -213,12 +220,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "C",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 51..52,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 51..52,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -230,12 +239,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "B",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 29..30,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 29..30,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -276,12 +287,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "C",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 51..52,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 51..52,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -293,12 +306,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "B",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 29..30,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 29..30,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -340,12 +355,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "B",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 23..24,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 23..24,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -353,12 +370,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "X",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 55..56,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 55..56,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -371,12 +390,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "A",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..8,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..8,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -384,12 +405,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "X",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 55..56,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 55..56,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -435,12 +458,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Iterator",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -448,12 +473,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Item",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -467,12 +494,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Iterator",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -480,12 +509,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Item",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -499,12 +530,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Iterator",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -512,12 +545,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Item",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -531,12 +566,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "MyIter",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -577,12 +614,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Struct",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..13,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..13,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -594,12 +633,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Struct",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..13,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..13,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -611,12 +652,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Struct",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..13,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..13,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -628,12 +671,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "self",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 42..46,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 42..46,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
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 90b8be64a46..3767d34e2c7 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
@@ -11,7 +11,10 @@ use syntax::{
     match_ast, SyntaxKind, SyntaxNode, T,
 };
 
-use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
+use crate::{
+    inlay_hints::LazyProperty, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig,
+    InlayKind,
+};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -141,7 +144,7 @@ pub(super) fn hints(
     acc.push(InlayHint {
         range: closing_token.text_range(),
         kind: InlayKind::ClosingBrace,
-        label: InlayHintLabel::simple(label, None, linked_location),
+        label: InlayHintLabel::simple(label, None, linked_location.map(LazyProperty::Computed)),
         text_edit: None,
         position: InlayHintPosition::After,
         pad_left: true,
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 906f2acf0c4..3e91618d08e 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
@@ -53,10 +53,6 @@ pub(super) fn hints(
     let last = captures.len() - 1;
     for (idx, capture) in captures.into_iter().enumerate() {
         let local = capture.local();
-        let source = local.primary_source(sema.db);
-
-        // force cache the source file, otherwise sema lookup will potentially panic
-        _ = sema.parse_or_expand(source.file());
 
         let label = format!(
             "{}{}",
@@ -73,8 +69,17 @@ pub(super) fn hints(
         }
         hint.label.append_part(InlayHintLabelPart {
             text: label,
-            linked_location: source.name().and_then(|name| {
-                name.syntax().original_file_range_opt(sema.db).map(TupleExt::head).map(Into::into)
+            linked_location: config.lazy_location_opt(|| {
+                let source = local.primary_source(sema.db);
+
+                // force cache the source file, otherwise sema lookup will potentially panic
+                _ = sema.parse_or_expand(source.file());
+                source.name().and_then(|name| {
+                    name.syntax()
+                        .original_file_range_opt(sema.db)
+                        .map(TupleExt::head)
+                        .map(Into::into)
+                })
             }),
             tooltip: None,
         });
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
index 037b328d971..762a4c26551 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
@@ -1,17 +1,19 @@
 //! Implementation of inlay hints for generic parameters.
-use ide_db::{active_parameter::generic_def_for_node, RootDatabase};
+use ide_db::{active_parameter::generic_def_for_node, famous_defs::FamousDefs};
 use syntax::{
     ast::{self, AnyHasGenericArgs, HasGenericArgs, HasName},
     AstNode,
 };
 
-use crate::{inlay_hints::GenericParameterHints, InlayHint, InlayHintsConfig, InlayKind};
+use crate::{
+    inlay_hints::GenericParameterHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
+};
 
-use super::param_name::{is_argument_similar_to_param_name, render_label};
+use super::param_name::is_argument_similar_to_param_name;
 
 pub(crate) fn hints(
     acc: &mut Vec<InlayHint>,
-    sema: &hir::Semantics<'_, RootDatabase>,
+    FamousDefs(sema, krate): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     node: AnyHasGenericArgs,
 ) -> Option<()> {
@@ -45,12 +47,23 @@ pub(crate) fn hints(
             return None;
         }
 
-        let name = param.name(sema.db);
-        let param_name = name.as_str();
+        let allowed = match (param, &arg) {
+            (hir::GenericParam::TypeParam(_), ast::GenericArg::TypeArg(_)) => type_hints,
+            (hir::GenericParam::ConstParam(_), ast::GenericArg::ConstArg(_)) => const_hints,
+            (hir::GenericParam::LifetimeParam(_), ast::GenericArg::LifetimeArg(_)) => {
+                lifetime_hints
+            }
+            _ => false,
+        };
+        if !allowed {
+            return None;
+        }
+
+        let param_name = param.name(sema.db);
 
         let should_hide = {
             let argument = get_string_representation(&arg)?;
-            is_argument_similar_to_param_name(&argument, param_name)
+            is_argument_similar_to_param_name(&argument, param_name.as_str())
         };
 
         if should_hide {
@@ -59,30 +72,28 @@ pub(crate) fn hints(
 
         let range = sema.original_range_opt(arg.syntax())?.range;
 
-        let source_syntax = match param {
-            hir::GenericParam::TypeParam(it) => {
-                if !type_hints || !matches!(arg, ast::GenericArg::TypeArg(_)) {
-                    return None;
-                }
-                sema.source(it.merge())?.value.syntax().clone()
-            }
-            hir::GenericParam::ConstParam(it) => {
-                if !const_hints || !matches!(arg, ast::GenericArg::ConstArg(_)) {
-                    return None;
-                }
-                let syntax = sema.source(it.merge())?.value.syntax().clone();
-                let const_param = ast::ConstParam::cast(syntax)?;
-                const_param.name()?.syntax().clone()
-            }
-            hir::GenericParam::LifetimeParam(it) => {
-                if !lifetime_hints || !matches!(arg, ast::GenericArg::LifetimeArg(_)) {
-                    return None;
-                }
-                sema.source(it)?.value.syntax().clone()
-            }
-        };
-        let linked_location = sema.original_range_opt(&source_syntax);
-        let label = render_label(param_name, config, linked_location);
+        let colon = if config.render_colons { ":" } else { "" };
+        let label = InlayHintLabel::simple(
+            format!("{}{colon}", param_name.display(sema.db, krate.edition(sema.db))),
+            None,
+            config.lazy_location_opt(|| {
+                let source_syntax = match param {
+                    hir::GenericParam::TypeParam(it) => {
+                        sema.source(it.merge()).map(|it| it.value.syntax().clone())
+                    }
+                    hir::GenericParam::ConstParam(it) => {
+                        let syntax = sema.source(it.merge())?.value.syntax().clone();
+                        let const_param = ast::ConstParam::cast(syntax)?;
+                        const_param.name().map(|it| it.syntax().clone())
+                    }
+                    hir::GenericParam::LifetimeParam(it) => {
+                        sema.source(it).map(|it| it.value.syntax().clone())
+                    }
+                };
+                let linked_location = source_syntax.and_then(|it| sema.original_range_opt(&it));
+                linked_location.map(Into::into)
+            }),
+        );
 
         Some(InlayHint {
             range,
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 1358d3722f8..27c7c3d4981 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
@@ -49,7 +49,7 @@ pub(super) fn hints(
             if mir.locals[place.local].ty.adt_id(ChalkTyInterner).is_none() {
                 continue; // Arguably only ADTs have significant drop impls
             }
-            let Some(binding) = local_to_binding.get(place.local) else {
+            let Some(&binding_idx) = local_to_binding.get(place.local) else {
                 continue; // Ignore temporary values
             };
             let range = match terminator.span {
@@ -91,25 +91,26 @@ pub(super) fn hints(
                 },
                 MirSpan::Unknown => continue,
             };
-            let binding_source = source_map
-                .patterns_for_binding(*binding)
-                .first()
-                .and_then(|d| source_map.pat_syntax(*d).ok())
-                .and_then(|d| {
-                    Some(FileRange {
-                        file_id: d.file_id.file_id()?.into(),
-                        range: d.value.text_range(),
-                    })
-                });
-            let binding = &hir.bindings[*binding];
+            let binding = &hir.bindings[binding_idx];
             let name = binding.name.display_no_db(file_id.edition()).to_smolstr();
             if name.starts_with("<ra@") {
                 continue; // Ignore desugared variables
             }
             let mut label = InlayHintLabel::simple(
                 name,
-                Some(config.lazy_tooltip(|| crate::InlayTooltip::String("moz".into()))),
-                binding_source,
+                None,
+                config.lazy_location_opt(|| {
+                    source_map
+                        .patterns_for_binding(binding_idx)
+                        .first()
+                        .and_then(|d| source_map.pat_syntax(*d).ok())
+                        .and_then(|d| {
+                            Some(FileRange {
+                                file_id: d.file_id.file_id()?.into(),
+                                range: d.value.text_range(),
+                            })
+                        })
+                }),
             );
             label.prepend_str("drop(");
             label.append_str(")");
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 a7b066700c5..8f01b1bd38b 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
@@ -3,7 +3,6 @@
 //! fn max(x: i32, y: i32) -> i32 { x + y }
 //! _ = max(/*x*/4, /*y*/4);
 //! ```
-use std::fmt::Display;
 
 use either::Either;
 use hir::{Callable, Semantics};
@@ -20,7 +19,7 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
-    FamousDefs(sema, _): &FamousDefs<'_, '_>,
+    FamousDefs(sema, krate): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     _file_id: EditionedFileId,
     expr: ast::Expr,
@@ -37,23 +36,29 @@ pub(super) fn hints(
         .filter_map(|(p, arg)| {
             // Only annotate hints for expressions that exist in the original file
             let range = sema.original_range_opt(arg.syntax())?;
-            let source = sema.source(p)?;
-            let (param_name, name_syntax) = match source.value.as_ref() {
-                Either::Left(pat) => (pat.name()?, pat.name()),
-                Either::Right(param) => match param.pat()? {
-                    ast::Pat::IdentPat(it) => (it.name()?, it.name()),
-                    _ => return None,
-                },
-            };
-            Some((name_syntax, param_name, arg, range))
+            let param_name = p.name(sema.db)?;
+            Some((p, param_name, arg, range))
         })
         .filter(|(_, param_name, arg, _)| {
-            !should_hide_param_name_hint(sema, &callable, &param_name.text(), arg)
+            !should_hide_param_name_hint(sema, &callable, param_name.as_str(), arg)
         })
         .map(|(param, param_name, _, hir::FileRange { range, .. })| {
-            let linked_location = param.and_then(|name| sema.original_range_opt(name.syntax()));
-
-            let label = render_label(&param_name, config, linked_location);
+            let colon = if config.render_colons { ":" } else { "" };
+            let label = InlayHintLabel::simple(
+                format!("{}{colon}", param_name.display(sema.db, krate.edition(sema.db))),
+                None,
+                config.lazy_location_opt(|| {
+                    let source = sema.source(param)?;
+                    let name_syntax = match source.value.as_ref() {
+                        Either::Left(pat) => pat.name(),
+                        Either::Right(param) => match param.pat()? {
+                            ast::Pat::IdentPat(it) => it.name(),
+                            _ => None,
+                        },
+                    }?;
+                    sema.original_range_opt(name_syntax.syntax()).map(Into::into)
+                }),
+            );
             InlayHint {
                 range,
                 kind: InlayKind::Parameter,
@@ -70,16 +75,6 @@ pub(super) fn hints(
     Some(())
 }
 
-pub(super) fn render_label(
-    param_name: impl Display,
-    config: &InlayHintsConfig,
-    linked_location: Option<hir::FileRange>,
-) -> InlayHintLabel {
-    let colon = if config.render_colons { ":" } else { "" };
-
-    InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location.map(Into::into))
-}
-
 fn get_callable(
     sema: &Semantics<'_, RootDatabase>,
     expr: &ast::Expr,
@@ -124,9 +119,7 @@ fn should_hide_param_name_hint(
     }
 
     let fn_name = match callable.kind() {
-        hir::CallableKind::Function(it) => {
-            Some(it.name(sema.db).unescaped().display_no_db().to_smolstr())
-        }
+        hir::CallableKind::Function(it) => Some(it.name(sema.db).as_str().to_smolstr()),
         _ => None,
     };
     let fn_name = fn_name.as_deref();
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 346e2862b0f..e942f5a6aac 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -91,7 +91,8 @@ pub use crate::{
     inlay_hints::{
         AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
         GenericParameterHints, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart,
-        InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
+        InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LazyProperty,
+        LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
@@ -671,7 +672,7 @@ impl Analysis {
         &self,
         config: &CompletionConfig<'_>,
         position: FilePosition,
-        imports: impl IntoIterator<Item = (String, String)> + std::panic::UnwindSafe,
+        imports: impl IntoIterator<Item = String> + std::panic::UnwindSafe,
     ) -> Cancellable<Vec<TextEdit>> {
         Ok(self
             .with_db(|db| ide_completion::resolve_completion_edits(db, config, position, imports))?
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index ba739df3092..07dfd83c4eb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -263,7 +263,7 @@ fn find_definitions(
                         .and_then(|def| {
                             // if the name differs from the definitions name it has to be an alias
                             if def
-                                .name(sema.db).is_some_and(|it| !it.eq_ident(name_ref.text().as_str()))
+                                .name(sema.db).is_some_and(|it| it.as_str() != name_ref.text().trim_start_matches("r#"))
                             {
                                 Err(format_err!("Renaming aliases is currently unsupported"))
                             } else {
diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml
index 5e7ee54c6af..c0358ef929b 100644
--- a/src/tools/rust-analyzer/crates/intern/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml
@@ -19,7 +19,6 @@ dashmap.workspace = true
 hashbrown.workspace = true
 rustc-hash.workspace = true
 triomphe.workspace = true
-sptr = "0.3.2"
 
 [lints]
 workspace = true
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
index 200b14027f8..b3bf285edfb 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
@@ -13,7 +13,6 @@ use std::{
 use dashmap::{DashMap, SharedValue};
 use hashbrown::{hash_map::RawEntryMut, HashMap};
 use rustc_hash::FxHasher;
-use sptr::Strict;
 use triomphe::Arc;
 
 pub mod symbols;
@@ -84,7 +83,7 @@ impl TaggedArcPtr {
     #[inline]
     pub(crate) unsafe fn try_as_arc_owned(self) -> Option<ManuallyDrop<Arc<Box<str>>>> {
         // Unpack the tag from the alignment niche
-        let tag = Strict::addr(self.packed.as_ptr()) & Self::BOOL_BITS;
+        let tag = self.packed.as_ptr().addr() & Self::BOOL_BITS;
         if tag != 0 {
             // Safety: We checked that the tag is non-zero -> true, so we are pointing to the data offset of an `Arc`
             Some(ManuallyDrop::new(unsafe {
@@ -99,40 +98,18 @@ impl TaggedArcPtr {
     fn pack_arc(ptr: NonNull<*const str>) -> NonNull<*const str> {
         let packed_tag = true as usize;
 
-        // can't use this strict provenance stuff here due to trait methods not being const
-        // unsafe {
-        //     // Safety: The pointer is derived from a non-null
-        //     NonNull::new_unchecked(Strict::map_addr(ptr.as_ptr(), |addr| {
-        //         // Safety:
-        //         // - The pointer is `NonNull` => it's address is `NonZero<usize>`
-        //         // - `P::BITS` least significant bits are always zero (`Pointer` contract)
-        //         // - `T::BITS <= P::BITS` (from `Self::ASSERTION`)
-        //         //
-        //         // Thus `addr >> T::BITS` is guaranteed to be non-zero.
-        //         //
-        //         // `{non_zero} | packed_tag` can't make the value zero.
-
-        //         (addr >> Self::BOOL_BITS) | packed_tag
-        //     }))
-        // }
-        // so what follows is roughly what the above looks like but inlined
-
-        let self_addr = ptr.as_ptr() as *const *const str as usize;
-        let addr = self_addr | packed_tag;
-        let dest_addr = addr as isize;
-        let offset = dest_addr.wrapping_sub(self_addr as isize);
-
-        // SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes
-        unsafe { NonNull::new_unchecked(ptr.as_ptr().cast::<u8>().wrapping_offset(offset).cast()) }
+        unsafe {
+            // Safety: The pointer is derived from a non-null and bit-oring it with true (1) will
+            // not make it null.
+            NonNull::new_unchecked(ptr.as_ptr().map_addr(|addr| addr | packed_tag))
+        }
     }
 
     #[inline]
     pub(crate) fn pointer(self) -> NonNull<*const str> {
         // SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes
         unsafe {
-            NonNull::new_unchecked(Strict::map_addr(self.packed.as_ptr(), |addr| {
-                addr & !Self::BOOL_BITS
-            }))
+            NonNull::new_unchecked(self.packed.as_ptr().map_addr(|addr| addr & !Self::BOOL_BITS))
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index b3b46421b50..ae1c6efe0cb 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -240,8 +240,10 @@ define_symbols! {
     format_unsafe_arg,
     format,
     freeze,
+    from,
     From,
     FromStr,
+    from_str,
     from_output,
     from_residual,
     from_usize,
@@ -273,6 +275,8 @@ define_symbols! {
     index_mut,
     index,
     Index,
+    into,
+    Into,
     into_future,
     into_iter,
     IntoFuture,
@@ -359,8 +363,10 @@ define_symbols! {
     panic_location,
     panic_misaligned_pointer_dereference,
     panic_nounwind,
+    panic_null_pointer_dereference,
     panic,
     Param,
+    parse,
     partial_ord,
     PartialEq,
     PartialOrd,
@@ -389,6 +395,7 @@ define_symbols! {
     RangeToInclusive,
     Ready,
     receiver,
+    receiver_target,
     recursion_limit,
     register_attr,
     register_tool,
@@ -454,13 +461,17 @@ define_symbols! {
     termination,
     test_case,
     test,
+    then,
     thiscall,
+    to_string,
     trace_macros,
     transmute_opts,
     transmute_trait,
     transparent,
+    try_into,
     Try,
     TryFrom,
+    try_from,
     tuple_trait,
     u128,
     u16,
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 00446b27cf2..5654c04a592 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -256,6 +256,24 @@ impl ProjectFolders {
             fsc.add_file_set(file_set_roots)
         }
 
+        for ws in workspaces.iter() {
+            let mut file_set_roots: Vec<VfsPath> = vec![];
+            let mut entries = vec![];
+
+            for buildfile in ws.buildfiles() {
+                file_set_roots.push(VfsPath::from(buildfile.to_owned()));
+                entries.push(buildfile.to_owned());
+            }
+
+            if !file_set_roots.is_empty() {
+                let entry = vfs::loader::Entry::Files(entries);
+                res.watch.push(res.load.len());
+                res.load.push(entry);
+                local_filesets.push(fsc.len() as u64);
+                fsc.add_file_set(file_set_roots)
+            }
+        }
+
         if let Some(user_config_path) = user_config_dir_path {
             let ratoml_path = {
                 let mut p = user_config_path.to_path_buf();
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index c7614849e01..59293ee3f96 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -392,12 +392,12 @@ impl server::Span for RaSpanServer {
 
     fn line(&mut self, _span: Self::Span) -> usize {
         // FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL
-        0
+        1
     }
 
     fn column(&mut self, _span: Self::Span) -> usize {
         // FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL
-        0
+        1
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
index 466eb14b55e..409cf3cc781 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -291,11 +291,11 @@ impl server::Span for TokenIdServer {
     }
 
     fn line(&mut self, _span: Self::Span) -> usize {
-        0
+        1
     }
 
     fn column(&mut self, _span: Self::Span) -> usize {
-        0
+        1
     }
 }
 
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 6a88cf022df..a3963967610 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
@@ -63,7 +63,7 @@ use crate::{ManifestPath, TargetKind};
 pub struct ProjectJson {
     /// e.g. `path/to/sysroot`
     pub(crate) sysroot: Option<AbsPathBuf>,
-    /// e.g. `path/to/sysroot/lib/rustlib/src/rust`
+    /// e.g. `path/to/sysroot/lib/rustlib/src/rust/library`
     pub(crate) sysroot_src: Option<AbsPathBuf>,
     project_root: AbsPathBuf,
     /// The path to the rust-project.json file. May be None if this
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
index 4bf9b59e7d0..e472da0c89b 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
@@ -19,7 +19,7 @@ pub fn get(
     let rustc_cfgs = match rustc_cfgs {
         Ok(cfgs) => cfgs,
         Err(e) => {
-            tracing::error!(?e, "failed to get rustc cfgs");
+            tracing::warn!(?e, "failed to get rustc cfgs");
             return vec![];
         }
     };
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 f98d983ac06..dcd62753cb2 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -524,6 +524,17 @@ impl ProjectWorkspace {
         }
     }
 
+    pub fn buildfiles(&self) -> Vec<AbsPathBuf> {
+        match &self.kind {
+            ProjectWorkspaceKind::Json(project) => project
+                .crates()
+                .filter_map(|(_, krate)| krate.build.as_ref().map(|build| build.build_file.clone()))
+                .map(|build_file| self.workspace_root().join(build_file))
+                .collect(),
+            _ => vec![],
+        }
+    }
+
     pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
         self.sysroot.discover_proc_macro_srv()
     }
@@ -568,27 +579,15 @@ impl ProjectWorkspace {
         match &self.kind {
             ProjectWorkspaceKind::Json(project) => project
                 .crates()
-                .map(|(_, krate)| {
-                    // FIXME: PackageRoots dont allow specifying files, only directories
-                    let build_file = krate
-                        .build
-                        .as_ref()
-                        .map(|build| self.workspace_root().join(&build.build_file))
-                        .as_deref()
-                        .and_then(AbsPath::parent)
-                        .map(ToOwned::to_owned);
-
-                    PackageRoot {
-                        is_local: krate.is_workspace_member,
-                        include: krate
-                            .include
-                            .iter()
-                            .cloned()
-                            .chain(build_file)
-                            .chain(self.extra_includes.iter().cloned())
-                            .collect(),
-                        exclude: krate.exclude.clone(),
-                    }
+                .map(|(_, krate)| PackageRoot {
+                    is_local: krate.is_workspace_member,
+                    include: krate
+                        .include
+                        .iter()
+                        .cloned()
+                        .chain(self.extra_includes.iter().cloned())
+                        .collect(),
+                    exclude: krate.exclude.clone(),
                 })
                 .collect::<FxHashSet<_>>()
                 .into_iter()
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 bcaec520195..18c27c84496 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
@@ -465,6 +465,7 @@ impl flags::AnalysisStats {
                                 prefer_no_std: false,
                                 prefer_prelude: true,
                                 prefer_absolute: false,
+                                allow_unstable: true,
                             },
                             Edition::LATEST,
                         )
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 3dc4379258f..44325fa1a29 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -453,6 +453,10 @@ config_data! {
         ///
         /// In `match` arms it completes a comma instead.
         completion_addSemicolonToUnit: bool = true,
+        /// Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.
+        completion_autoAwait_enable: bool        = true,
+        /// Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.
+        completion_autoIter_enable: bool        = true,
         /// Toggles the additional completions that automatically add imports when completed.
         /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
         completion_autoimport_enable: bool       = true,
@@ -1484,6 +1488,8 @@ impl Config {
             enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
                 && self.caps.completion_item_edit_resolve(),
             enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(),
+            enable_auto_iter: *self.completion_autoIter_enable(source_root),
+            enable_auto_await: *self.completion_autoAwait_enable(source_root),
             enable_private_editable: self.completion_privateEditable_enable(source_root).to_owned(),
             full_function_signatures: self
                 .completion_fullFunctionSignatures_enable(source_root)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index 22f06d68d80..2309f94a742 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -88,6 +88,17 @@ pub(crate) enum FlycheckConfig {
     },
 }
 
+impl FlycheckConfig {
+    pub(crate) fn invocation_strategy_once(&self) -> bool {
+        match self {
+            FlycheckConfig::CargoCommand { .. } => false,
+            FlycheckConfig::CustomCommand { invocation_strategy, .. } => {
+                *invocation_strategy == InvocationStrategy::Once
+            }
+        }
+    }
+}
+
 impl fmt::Display for FlycheckConfig {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
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 98efc637c2c..84ba89d9f31 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
@@ -291,9 +291,15 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
     let file_id = state.vfs.read().0.file_id(&vfs_path);
     if let Some(file_id) = file_id {
         let world = state.snapshot();
+        let invocation_strategy_once = state.config.flycheck(None).invocation_strategy_once();
         let may_flycheck_workspace = state.config.flycheck_workspace(None);
         let mut updated = false;
         let task = move || -> std::result::Result<(), ide::Cancelled> {
+            if invocation_strategy_once {
+                let saved_file = vfs_path.as_path().map(|p| p.to_owned());
+                world.flycheck[0].restart_workspace(saved_file.clone());
+            }
+
             let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| {
                 let tgt_kind = it.target_kind();
                 let (tgt_name, root, package) = match it {
@@ -320,16 +326,15 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                 // the user opted into package checks then
                 let package_check_allowed = target.is_some() || !may_flycheck_workspace;
                 if package_check_allowed {
-                    let workspace =
-                        world.workspaces.iter().enumerate().find(|(_, ws)| match &ws.kind {
-                            project_model::ProjectWorkspaceKind::Cargo { cargo, .. }
-                            | project_model::ProjectWorkspaceKind::DetachedFile {
-                                cargo: Some((cargo, _, _)),
-                                ..
-                            } => *cargo.workspace_root() == root,
-                            _ => false,
-                        });
-                    if let Some((idx, _)) = workspace {
+                    let workspace = world.workspaces.iter().position(|ws| match &ws.kind {
+                        project_model::ProjectWorkspaceKind::Cargo { cargo, .. }
+                        | project_model::ProjectWorkspaceKind::DetachedFile {
+                            cargo: Some((cargo, _, _)),
+                            ..
+                        } => *cargo.workspace_root() == root,
+                        _ => false,
+                    });
+                    if let Some(idx) = workspace {
                         world.flycheck[idx].restart_for_package(package, target);
                     }
                 }
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 190015d7faa..39cbf53eaa2 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
@@ -1154,10 +1154,7 @@ pub(crate) fn handle_completion_resolve(
             .resolve_completion_edits(
                 &forced_resolve_completions_config,
                 position,
-                resolve_data
-                    .imports
-                    .into_iter()
-                    .map(|import| (import.full_import_path, import.imported_name)),
+                resolve_data.imports.into_iter().map(|import| import.full_import_path),
             )?
             .into_iter()
             .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel)))
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 fcfd06679bf..5cdc51a1c19 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
@@ -176,6 +176,8 @@ fn integrated_completion_benchmark() {
             fields_to_resolve: CompletionFieldsToResolve::empty(),
             exclude_flyimport: vec![],
             exclude_traits: &[],
+            enable_auto_await: true,
+            enable_auto_iter: true,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -226,6 +228,8 @@ fn integrated_completion_benchmark() {
             fields_to_resolve: CompletionFieldsToResolve::empty(),
             exclude_flyimport: vec![],
             exclude_traits: &[],
+            enable_auto_await: true,
+            enable_auto_iter: true,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -274,6 +278,8 @@ fn integrated_completion_benchmark() {
             fields_to_resolve: CompletionFieldsToResolve::empty(),
             exclude_flyimport: vec![],
             exclude_traits: &[],
+            enable_auto_await: true,
+            enable_auto_iter: true,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 61ec576dd4f..ccffa7a671e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -142,9 +142,8 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
         hasher.update(prefix);
         hasher.update(u32::from(*text_size).to_le_bytes());
     }
-    for (import_path, import_name) in &item.import_to_add {
+    for import_path in &item.import_to_add {
         hasher.update(import_path);
-        hasher.update(import_name);
     }
     hasher.finalize()
 }
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 134de92feab..ca4372aa83f 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
@@ -850,7 +850,6 @@ pub struct InlayHintResolveData {
 #[derive(Debug, Serialize, Deserialize)]
 pub struct CompletionImport {
     pub full_import_path: String,
-    pub imported_name: String,
 }
 
 #[derive(Debug, Deserialize, Default)]
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 a5516e7f9d4..bff53cf98b7 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
@@ -11,8 +11,8 @@ use ide::{
     Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve,
     CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange,
     FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel,
-    InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup,
-    NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
+    InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, LazyProperty,
+    Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
     SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
 };
 use ide_db::{assists, rust_doc::format_docs, FxHasher};
@@ -394,10 +394,7 @@ fn completion_item(
             item.import_to_add
                 .clone()
                 .into_iter()
-                .map(|(import_path, import_name)| lsp_ext::CompletionImport {
-                    full_import_path: import_path,
-                    imported_name: import_name,
-                })
+                .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
                 .collect()
         } else {
             Vec::new()
@@ -549,12 +546,11 @@ pub(crate) fn inlay_hint(
 ) -> Cancellable<lsp_types::InlayHint> {
     let hint_needs_resolve = |hint: &InlayHint| -> Option<TextRange> {
         hint.resolve_parent.filter(|_| {
-            hint.text_edit.is_some()
-                || hint
-                    .label
-                    .parts
-                    .iter()
-                    .any(|part| part.linked_location.is_some() || part.tooltip.is_some())
+            hint.text_edit.as_ref().is_some_and(LazyProperty::is_lazy)
+                || hint.label.parts.iter().any(|part| {
+                    part.linked_location.as_ref().is_some_and(LazyProperty::is_lazy)
+                        || part.tooltip.as_ref().is_some_and(LazyProperty::is_lazy)
+                })
         })
     };
 
@@ -569,22 +565,21 @@ pub(crate) fn inlay_hint(
     });
 
     let mut something_to_resolve = false;
-    let text_edits = if snap
-        .config
-        .visual_studio_code_version()
-        .is_none_or(|version| VersionReq::parse(">=1.86.0").unwrap().matches(version))
-        && resolve_range_and_hash.is_some()
-        && fields_to_resolve.resolve_text_edits
-    {
-        something_to_resolve |= inlay_hint.text_edit.is_some();
-        None
-    } else {
-        inlay_hint
-            .text_edit
-            .take()
-            .and_then(|it| it.computed())
-            .map(|it| text_edit_vec(line_index, it))
-    };
+    let text_edits = inlay_hint
+        .text_edit
+        .take()
+        .and_then(|it| match it {
+            LazyProperty::Computed(it) => Some(it),
+            LazyProperty::Lazy => {
+                something_to_resolve |=
+                    snap.config.visual_studio_code_version().is_none_or(|version| {
+                        VersionReq::parse(">=1.86.0").unwrap().matches(version)
+                    }) && resolve_range_and_hash.is_some()
+                        && fields_to_resolve.resolve_text_edits;
+                None
+            }
+        })
+        .map(|it| text_edit_vec(line_index, it));
     let (label, tooltip) = inlay_hint_label(
         snap,
         fields_to_resolve,
@@ -637,22 +632,23 @@ fn inlay_hint_label(
     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();
-                None
-            } else {
-                match tooltip.and_then(|it| it.computed()) {
-                    Some(ide::InlayTooltip::String(s)) => {
-                        Some(lsp_types::InlayHintTooltip::String(s))
-                    }
-                    Some(ide::InlayTooltip::Markdown(s)) => {
-                        Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent {
-                            kind: lsp_types::MarkupKind::Markdown,
-                            value: s,
-                        }))
-                    }
-                    None => None,
+            let tooltip = tooltip.and_then(|it| match it {
+                LazyProperty::Computed(it) => Some(it),
+                LazyProperty::Lazy => {
+                    *something_to_resolve |=
+                        needs_resolve && fields_to_resolve.resolve_hint_tooltip;
+                    None
                 }
+            });
+            let hint_tooltip = match tooltip {
+                Some(ide::InlayTooltip::String(s)) => Some(lsp_types::InlayHintTooltip::String(s)),
+                Some(ide::InlayTooltip::Markdown(s)) => {
+                    Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent {
+                        kind: lsp_types::MarkupKind::Markdown,
+                        value: s,
+                    }))
+                }
+                None => None,
             };
             (lsp_types::InlayHintLabel::String(text), hint_tooltip)
         }
@@ -661,31 +657,38 @@ fn inlay_hint_label(
                 .parts
                 .into_iter()
                 .map(|part| {
-                    let tooltip = if needs_resolve && fields_to_resolve.resolve_label_tooltip {
-                        *something_to_resolve |= part.tooltip.is_some();
-                        None
-                    } else {
-                        match part.tooltip.and_then(|it| it.computed()) {
-                            Some(ide::InlayTooltip::String(s)) => {
-                                Some(lsp_types::InlayHintLabelPartTooltip::String(s))
-                            }
-                            Some(ide::InlayTooltip::Markdown(s)) => {
-                                Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
-                                    lsp_types::MarkupContent {
-                                        kind: lsp_types::MarkupKind::Markdown,
-                                        value: s,
-                                    },
-                                ))
-                            }
-                            None => None,
+                    let tooltip = part.tooltip.and_then(|it| match it {
+                        LazyProperty::Computed(it) => Some(it),
+                        LazyProperty::Lazy => {
+                            *something_to_resolve |= fields_to_resolve.resolve_label_tooltip;
+                            None
                         }
+                    });
+                    let tooltip = match tooltip {
+                        Some(ide::InlayTooltip::String(s)) => {
+                            Some(lsp_types::InlayHintLabelPartTooltip::String(s))
+                        }
+                        Some(ide::InlayTooltip::Markdown(s)) => {
+                            Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
+                                lsp_types::MarkupContent {
+                                    kind: lsp_types::MarkupKind::Markdown,
+                                    value: s,
+                                },
+                            ))
+                        }
+                        None => None,
                     };
-                    let location = if needs_resolve && fields_to_resolve.resolve_label_location {
-                        *something_to_resolve |= part.linked_location.is_some();
-                        None
-                    } else {
-                        part.linked_location.map(|range| location(snap, range)).transpose()?
-                    };
+                    let location = part
+                        .linked_location
+                        .and_then(|it| match it {
+                            LazyProperty::Computed(it) => Some(it),
+                            LazyProperty::Lazy => {
+                                *something_to_resolve |= fields_to_resolve.resolve_label_location;
+                                None
+                            }
+                        })
+                        .map(|range| location(snap, range))
+                        .transpose()?;
                     Ok(lsp_types::InlayHintLabelPart {
                         value: part.text,
                         tooltip,
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index dca231604fa..ff027ac5848 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -411,6 +411,11 @@ pub fn path_from_text(text: &str) -> ast::Path {
     ast_from_text(&format!("fn main() {{ let test: {text}; }}"))
 }
 
+// FIXME: should not be pub
+pub fn path_from_text_with_edition(text: &str, edition: Edition) -> ast::Path {
+    ast_from_text_with_edition(&format!("fn main() {{ let test: {text}; }}"), edition)
+}
+
 pub fn use_tree_glob() -> ast::UseTree {
     ast_from_text("use *;")
 }
@@ -1230,7 +1235,12 @@ pub fn token_tree(
 
 #[track_caller]
 fn ast_from_text<N: AstNode>(text: &str) -> N {
-    let parse = SourceFile::parse(text, Edition::CURRENT);
+    ast_from_text_with_edition(text, Edition::CURRENT)
+}
+
+#[track_caller]
+fn ast_from_text_with_edition<N: AstNode>(text: &str, edition: Edition) -> N {
+    let parse = SourceFile::parse(text, edition);
     let node = match parse.tree().syntax().descendants().find_map(N::cast) {
         Some(it) => it,
         None => {
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index fd06736a252..4ed68d18e80 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -53,6 +53,7 @@
 //!     pin:
 //!     pointee: copy, send, sync, ord, hash, unpin
 //!     range:
+//!     receiver: deref
 //!     result:
 //!     send: sized
 //!     size_of: sized
@@ -513,10 +514,26 @@ pub mod ops {
             fn deref_mut(&mut self) -> &mut Self::Target;
         }
         // endregion:deref_mut
+
+        // region:receiver
+        #[lang = "receiver"]
+        pub trait Receiver {
+            #[lang = "receiver_target"]
+            type Target: ?Sized;
+        }
+
+        impl<P: ?Sized, T: ?Sized> Receiver for P
+        where
+            P: Deref<Target = T>,
+        {
+            type Target = T;
+        }
+        // endregion:receiver
     }
     pub use self::deref::{
         Deref,
         DerefMut, // :deref_mut
+        Receiver, // :receiver
     };
     // endregion:deref
 
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md
index 3ba492e0959..c990212d585 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/dev/README.md
@@ -269,19 +269,13 @@ Note: we tag releases by dates, releasing a patch release on the same day should
 
 ## Permissions
 
-There are three sets of people with extra permissions:
+There are two sets of people with extra permissions:
 
-* rust-analyzer GitHub organization [**admins**](https://github.com/orgs/rust-analyzer/people?query=role:owner) (which include current t-compiler leads).
-  Admins have full access to the org.
-* [**review**](https://github.com/orgs/rust-analyzer/teams/review) team in the organization.
-  Reviewers have `r+` access to all of organization's repositories and publish rights on crates.io.
-  They also have direct commit access, but all changes should via bors queue.
+* The [rust-lang](https://github.com/rust-lang) team [t-rust-analyzer](https://github.com/rust-lang/team/blob/master/teams/rust-analyzer.toml).
+  This team has write access to the repository and merge queue permissions (note the repo itself is managed by infra admins).
   It's ok to self-approve if you think you know what you are doing!
-  bors should automatically sync the permissions.
   Feel free to request a review or assign any PR to a reviewer with the relevant expertise to bring the work to their attention.
   Don't feel pressured to review assigned PRs though.
-  If you don't feel like reviewing for whatever reason, someone else will pick the review up!
-* [**triage**](https://github.com/orgs/rust-analyzer/teams/triage) team in the organization.
-  This team can label and close issues.
-
-Note that at the time being you need to be a member of the org yourself to view the links.
+  If you don't feel like reviewing for whatever reason, someone else will pick the review up (but please speak up if you don't feel like it)!
+* The [rust-lang](https://github.com/rust-lang) team [t-rust-analyzer-contributors]([https://github.com/orgs/rust-analyzer/teams/triage](https://github.com/rust-lang/team/blob/master/teams/rust-analyzer-contributors.toml)).
+  This team has general triaging permissions allowing to label, close and re-open issues.
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index a632fc6f5fb..c7ee4e40236 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: 2d8604825c458288
+lsp/ext.rs hash: af70cce5d6905e39
 
 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:
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index bd091db58d3..b33de1956b8 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -274,6 +274,16 @@ Whether to automatically add a semicolon when completing unit-returning function
 
 In `match` arms it completes a comma instead.
 --
+[[rust-analyzer.completion.autoAwait.enable]]rust-analyzer.completion.autoAwait.enable (default: `true`)::
++
+--
+Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.
+--
+[[rust-analyzer.completion.autoIter.enable]]rust-analyzer.completion.autoIter.enable (default: `true`)::
++
+--
+Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.
+--
 [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
 +
 --
diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc
index ffc820e9b7f..4a2a6f2e368 100644
--- a/src/tools/rust-analyzer/docs/user/manual.adoc
+++ b/src/tools/rust-analyzer/docs/user/manual.adoc
@@ -716,6 +716,32 @@ interface JsonProject {
     /// dependencies as well as sysroot crate (libstd,
     /// libcore and such).
     crates: Crate[];
+    /// Configuration for CLI commands.
+    ///
+    /// These are used for running and debugging binaries
+    /// and tests without encoding build system-specific
+    /// knowledge into rust-analyzer.
+    ///
+    /// # Example
+    ///
+    /// Below is an example of a test runnable. `{label}` and `{test_id}`
+    /// are explained in `Runnable::args`'s documentation below.
+    ///
+    /// ```json
+    /// {
+    ///     "program": "buck",
+    ///     "args": [
+    ///         "test",
+    ///          "{label}",
+    ///          "--",
+    ///          "{test_id}",
+    ///          "--print-passing-details"
+    ///     ],
+    ///     "cwd": "/home/user/repo-root/",
+    ///     "kind": "testOne"
+    /// }
+    /// ```
+    runnables?: Runnable[];
 }
 
 interface Crate {
@@ -726,7 +752,10 @@ interface Crate {
     /// Path to the root module of the crate.
     root_module: string;
     /// Edition of the crate.
-    edition: "2015" | "2018" | "2021";
+    edition: '2015' | '2018' | '2021' | '2024';
+    /// The version of the crate. Used for calculating
+    /// the correct docs.rs URL.
+    version?: string;
     /// Dependencies
     deps: Dep[];
     /// Should this crate be treated as a member of
@@ -757,9 +786,9 @@ interface Crate {
     /// rust-analyzer assumes that files from one
     /// source can't refer to files in another source.
     source?: {
-        include_dirs: string[],
-        exclude_dirs: string[],
-    },
+        include_dirs: string[];
+        exclude_dirs: string[];
+    };
     /// List of cfg groups this crate inherits.
     ///
     /// All cfg in these groups will be concatenated to
@@ -776,21 +805,68 @@ interface Crate {
     target?: string;
     /// Environment variables, used for
     /// the `env!` macro
-    env: { [key: string]: string; },
+    env: { [key: string]: string; };
 
     /// Whether the crate is a proc-macro crate.
     is_proc_macro: boolean;
     /// For proc-macro crates, path to compiled
     /// proc-macro (.so file).
     proc_macro_dylib_path?: string;
+
+    /// Repository, matching the URL that would be used
+    /// in Cargo.toml.
+    repository?: string;
+
+    /// Build-specific data about this crate.
+    build?: BuildInfo;
 }
 
 interface Dep {
     /// Index of a crate in the `crates` array.
-    crate: number,
+    crate: number;
     /// Name as should appear in the (implicit)
     /// `extern crate name` declaration.
-    name: string,
+    name: string;
+}
+
+interface BuildInfo {
+    /// The name associated with this crate.
+    ///
+    /// This is determined by the build system that produced
+    /// the `rust-project.json` in question. For instance, if buck were used,
+    /// the label might be something like `//ide/rust/rust-analyzer:rust-analyzer`.
+    ///
+    /// Do not attempt to parse the contents of this string; it is a build system-specific
+    /// identifier similar to `Crate::display_name`.
+    label: string;
+    /// Path corresponding to the build system-specific file defining the crate.
+    build_file: string;
+    /// The kind of target.
+    ///
+    /// This information is used to determine what sort
+    /// of runnable codelens to provide, if any.
+    target_kind: 'bin' | 'lib' | 'test';
+}
+
+interface Runnable {
+    /// The program invoked by the runnable.
+    ///
+    /// For example, this might be `cargo`, `buck`, or `bazel`.
+    program: string;
+    /// The arguments passed to `program`.
+    args: string[];
+    /// The current working directory of the runnable.
+    cwd: string;
+    /// Used to decide what code lens to offer.
+    ///
+    /// `testOne`: This runnable will be used when the user clicks the 'Run Test'
+    /// CodeLens above a test.
+    ///
+    /// The args for testOne can contain two template strings:
+    /// `{label}` and `{test_id}`. `{label}` will be replaced
+    /// with the `Build::label` and `{test_id}` will be replaced
+    /// with the test name.
+    kind: 'testOne' | string;
 }
 ----
 
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 8b066377f2b..f148041ac3e 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -1146,6 +1146,26 @@
             {
                 "title": "completion",
                 "properties": {
+                    "rust-analyzer.completion.autoAwait.enable": {
+                        "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.autoIter.enable": {
+                        "markdownDescription": "Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
                     "rust-analyzer.completion.autoimport.enable": {
                         "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
                         "default": true,
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 5550bfa6558..96dc4f19b82 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -361,7 +361,14 @@ export class Ctx implements RustAnalyzerExtensionApi {
             }
         });
 
-        vscode.workspace.onDidChangeTextDocument(async () => {
+        vscode.workspace.onDidChangeTextDocument(async (e) => {
+            if (
+                vscode.window.activeTextEditor?.document !== e.document ||
+                e.contentChanges.length === 0
+            ) {
+                return;
+            }
+
             if (this.syntaxTreeView?.visible) {
                 await this.syntaxTreeProvider?.refresh();
             }
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
index 074bc43388a..2749557b91a 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
@@ -80,9 +80,9 @@ pub struct Request {
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct Response {
-    // JSON RPC allows this to be null if it was impossible
-    // to decode the request's id. Ignore this special case
-    // and just die horribly.
+    // JSON-RPC allows this to be null if we can't find or parse the
+    // request id. We fail deserialization in that case, so we just
+    // make this field mandatory.
     pub id: RequestId,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub result: Option<serde_json::Value>,
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 86d2abcacb7..b31bf61a6fb 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -150,9 +150,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.16.0"
+version = "3.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
 name = "byteorder"
@@ -191,9 +191,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.26"
+version = "4.5.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783"
+checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -201,9 +201,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.26"
+version = "4.5.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121"
+checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
 dependencies = [
  "anstream",
  "anstyle",
@@ -214,9 +214,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.42"
+version = "4.5.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0"
+checksum = "0952013545c9c6dca60f491602655b795c6c062ab180c9cb0bccb83135461861"
 dependencies = [
  "clap",
 ]
@@ -253,9 +253,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.16"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
 dependencies = [
  "libc",
 ]
@@ -750,9 +750,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.7.0"
+version = "2.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
+checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -867,9 +867,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.43"
+version = "0.4.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148"
+checksum = "f9da1e54401fe5d45a664c57e112e70f18e8c5a73e268c179305b932ee864574"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -1372,9 +1372,9 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.43"
+version = "0.38.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
 dependencies = [
  "bitflags 2.8.0",
  "errno",
@@ -1391,9 +1391,9 @@ checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
 
 [[package]]
 name = "ryu"
-version = "1.0.18"
+version = "1.0.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
 
 [[package]]
 name = "same-file"
@@ -1412,9 +1412,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "semver"
-version = "1.0.24"
+version = "1.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
+checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
 
 [[package]]
 name = "serde"
@@ -1438,9 +1438,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.135"
+version = "1.0.138"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
+checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
 dependencies = [
  "itoa",
  "memchr",
@@ -1732,9 +1732,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.14"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
 
 [[package]]
 name = "unicode-width"
@@ -1972,9 +1972,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
-version = "0.6.24"
+version = "0.6.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a"
+checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310"
 dependencies = [
  "memchr",
 ]
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index c2ce8fef4d0..9f9846cdee0 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -14,6 +14,6 @@ mdbook-i18n-helpers = "0.3.3"
 mdbook-spec = { path = "../../doc/reference/mdbook-spec" }
 
 [dependencies.mdbook]
-version = "0.4.37"
+version = "0.4.44"
 default-features = false
 features = ["search"]
diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs
index 34984798ae6..28df49b9304 100644
--- a/src/tools/rustfmt/src/bin/main.rs
+++ b/src/tools/rustfmt/src/bin/main.rs
@@ -817,7 +817,6 @@ mod test {
         options.inline_config = HashMap::from([("version".to_owned(), "Two".to_owned())]);
         let config = get_config(None, Some(options));
         assert_eq!(config.style_edition(), StyleEdition::Edition2024);
-        assert_eq!(config.overflow_delimited_expr(), true);
     }
 
     #[nightly_only_test]
@@ -827,7 +826,6 @@ mod test {
         let config_file = Some(Path::new("tests/config/style-edition/just-version"));
         let config = get_config(config_file, Some(options));
         assert_eq!(config.style_edition(), StyleEdition::Edition2024);
-        assert_eq!(config.overflow_delimited_expr(), true);
     }
 
     #[nightly_only_test]
@@ -872,7 +870,6 @@ mod test {
         ]);
         let config = get_config(None, Some(options));
         assert_eq!(config.style_edition(), StyleEdition::Edition2024);
-        assert_eq!(config.overflow_delimited_expr(), true);
     }
 
     #[nightly_only_test]
@@ -938,7 +935,6 @@ mod test {
         options.style_edition = Some(StyleEdition::Edition2024);
         let config = get_config(None, Some(options));
         assert_eq!(config.style_edition(), StyleEdition::Edition2024);
-        assert_eq!(config.overflow_delimited_expr(), true);
     }
 
     #[nightly_only_test]
@@ -948,6 +944,8 @@ mod test {
         let config_file = Some(Path::new("tests/config/style-edition/overrides"));
         let config = get_config(config_file, Some(options));
         assert_eq!(config.style_edition(), StyleEdition::Edition2024);
+        // FIXME: this test doesn't really exercise anything, since
+        // `overflow_delimited_expr` is disabled by default in edition 2024.
         assert_eq!(config.overflow_delimited_expr(), false);
     }
 
@@ -959,7 +957,8 @@ mod test {
         options.inline_config =
             HashMap::from([("overflow_delimited_expr".to_owned(), "false".to_owned())]);
         let config = get_config(config_file, Some(options));
-        assert_eq!(config.style_edition(), StyleEdition::Edition2024);
+        // FIXME: this test doesn't really exercise anything, since
+        // `overflow_delimited_expr` is disabled by default in edition 2024.
         assert_eq!(config.overflow_delimited_expr(), false);
     }
 }
diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs
index 7355adc9f9d..6b63108c037 100644
--- a/src/tools/rustfmt/src/config/mod.rs
+++ b/src/tools/rustfmt/src/config/mod.rs
@@ -848,7 +848,7 @@ binop_separator = "Front"
 remove_nested_parens = true
 combine_control_expr = true
 short_array_element_width_threshold = 10
-overflow_delimited_expr = true
+overflow_delimited_expr = false
 struct_field_align_threshold = 0
 enum_discrim_align_threshold = 0
 match_arm_blocks = true
diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs
index bbc99a2dced..71865ec75ce 100644
--- a/src/tools/rustfmt/src/config/options.rs
+++ b/src/tools/rustfmt/src/config/options.rs
@@ -627,7 +627,7 @@ config_option_with_style_edition_default!(
     RemoveNestedParens, bool, _ => true;
     CombineControlExpr, bool, _ => true;
     ShortArrayElementWidthThreshold, usize, _ => 10;
-    OverflowDelimitedExpr, bool, Edition2024 => true, _ => false;
+    OverflowDelimitedExpr, bool, _ => false;
     StructFieldAlignThreshold, usize, _ => 0;
     EnumDiscrimAlignThreshold, usize, _ => 0;
     MatchArmBlocks, bool, _ => true;
@@ -644,7 +644,7 @@ config_option_with_style_edition_default!(
     BlankLinesLowerBound, usize, _ => 0;
     EditionConfig, Edition, _ => Edition::Edition2015;
     StyleEditionConfig, StyleEdition,
-        Edition2024 =>  StyleEdition::Edition2024, _ => StyleEdition::Edition2015;
+        Edition2024 => StyleEdition::Edition2024, _ => StyleEdition::Edition2015;
     VersionConfig, Version, Edition2024 => Version::Two, _ => Version::One;
     InlineAttributeWidth, usize, _ => 0;
     FormatGeneratedFiles, bool, _ => true;
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 63cc8794cea..34077c5f866 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -114,14 +114,13 @@ fn default_dcx(
         false,
     );
     let emitter = Box::new(
-        HumanEmitter::new(stderr_destination(emit_color), fallback_bundle.clone())
+        HumanEmitter::new(stderr_destination(emit_color), fallback_bundle)
             .sm(Some(source_map.clone())),
     );
 
     let emitter: Box<DynEmitter> = if !show_parse_errors {
         Box::new(SilentEmitter {
-            fallback_bundle,
-            fatal_dcx: DiagCtxt::new(emitter),
+            fatal_emitter: emitter,
             fatal_note: None,
             emit_fatal_diagnostic: false,
         })
@@ -205,16 +204,7 @@ impl ParseSess {
     }
 
     pub(crate) fn set_silent_emitter(&mut self) {
-        // Ideally this invocation wouldn't be necessary and the fallback bundle in
-        // `self.parse_sess.dcx` could be used, but the lock in `DiagCtxt` prevents this.
-        // See `<rustc_errors::SilentEmitter as Translate>::fallback_fluent_bundle`.
-        let fallback_bundle = rustc_errors::fallback_fluent_bundle(
-            rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
-            false,
-        );
-        self.raw_psess
-            .dcx()
-            .make_silent(fallback_bundle, None, false);
+        self.raw_psess.dcx().make_silent(None, false);
     }
 
     pub(crate) fn span_to_filename(&self, span: Span) -> FileName {
diff --git a/src/tools/rustfmt/tests/target/configs/style_edition/overflow_delim_expr_2024.rs b/src/tools/rustfmt/tests/target/configs/style_edition/overflow_delim_expr_2024.rs
index ecd2e8ca797..1b2d12ce320 100644
--- a/src/tools/rustfmt/tests/target/configs/style_edition/overflow_delim_expr_2024.rs
+++ b/src/tools/rustfmt/tests/target/configs/style_edition/overflow_delim_expr_2024.rs
@@ -25,10 +25,13 @@ fn combine_blocklike() {
         y: value2,
     });
 
-    do_thing(x, Bar {
-        x: value,
-        y: value2,
-    });
+    do_thing(
+        x,
+        Bar {
+            x: value,
+            y: value2,
+        },
+    );
 
     do_thing(
         x,
@@ -46,12 +49,15 @@ fn combine_blocklike() {
         value4_with_longer_name,
     ]);
 
-    do_thing(x, &[
-        value_with_longer_name,
-        value2_with_longer_name,
-        value3_with_longer_name,
-        value4_with_longer_name,
-    ]);
+    do_thing(
+        x,
+        &[
+            value_with_longer_name,
+            value2_with_longer_name,
+            value3_with_longer_name,
+            value4_with_longer_name,
+        ],
+    );
 
     do_thing(
         x,
@@ -71,12 +77,15 @@ fn combine_blocklike() {
         value4_with_longer_name,
     ]);
 
-    do_thing(x, vec![
-        value_with_longer_name,
-        value2_with_longer_name,
-        value3_with_longer_name,
-        value4_with_longer_name,
-    ]);
+    do_thing(
+        x,
+        vec![
+            value_with_longer_name,
+            value2_with_longer_name,
+            value3_with_longer_name,
+            value4_with_longer_name,
+        ],
+    );
 
     do_thing(
         x,
@@ -99,22 +108,28 @@ fn combine_blocklike() {
 }
 
 fn combine_struct_sample() {
-    let identity = verify(&ctx, VerifyLogin {
-        type_: LoginType::Username,
-        username: args.username.clone(),
-        password: Some(args.password.clone()),
-        domain: None,
-    })?;
+    let identity = verify(
+        &ctx,
+        VerifyLogin {
+            type_: LoginType::Username,
+            username: args.username.clone(),
+            password: Some(args.password.clone()),
+            domain: None,
+        },
+    )?;
 }
 
 fn combine_macro_sample() {
     rocket::ignite()
-        .mount("/", routes![
-            http::auth::login,
-            http::auth::logout,
-            http::cors::options,
-            http::action::dance,
-            http::action::sleep,
-        ])
+        .mount(
+            "/",
+            routes![
+                http::auth::login,
+                http::auth::logout,
+                http::cors::options,
+                http::action::dance,
+                http::action::sleep,
+            ],
+        )
         .launch();
 }
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 6f0fd09b353..45b40b17ea3 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,3 +1 @@
 run-make/split-debuginfo/Makefile
-run-make/symbol-mangling-hashed/Makefile
-run-make/translation/Makefile
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index d158a8e6324..9b78ba75a05 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -134,7 +134,7 @@ mod os_impl {
             &mut |entry| {
                 let file = entry.path();
                 let extension = file.extension();
-                let scripts = ["py", "sh", "ps1"];
+                let scripts = ["py", "sh", "ps1", "woff2"];
                 if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) {
                     return;
                 }
diff --git a/tests/assembly/small_data_threshold.rs b/tests/assembly/small_data_threshold.rs
index d3ba144600e..bed515915b8 100644
--- a/tests/assembly/small_data_threshold.rs
+++ b/tests/assembly/small_data_threshold.rs
@@ -58,35 +58,35 @@ static mut Z: u64 = 0;
 // Currently, only MIPS and RISCV successfully put any objects in the small data
 // sections so the U/V/W/X tests are skipped on Hexagon and M68K
 
-//@ RISCV: .section .sdata
-//@ RISCV-NOT: .section
-//@ RISCV: U:
-//@ RISCV: .section .sbss
-//@ RISCV-NOT: .section
-//@ RISCV: V:
-//@ RISCV: .section .sdata
-//@ RISCV-NOT: .section
-//@ RISCV: W:
-//@ RISCV: .section .sbss
-//@ RISCV-NOT: .section
-//@ RISCV: X:
+// RISCV: .section .sdata
+// RISCV-NOT: .section
+// RISCV: U:
+// RISCV: .section .sbss
+// RISCV-NOT: .section
+// RISCV: V:
+// RISCV: .section .sdata
+// RISCV-NOT: .section
+// RISCV: W:
+// RISCV: .section .sbss
+// RISCV-NOT: .section
+// RISCV: X:
 
-//@ MIPS: .section .sdata
-//@ MIPS-NOT: .section
-//@ MIPS: U:
-//@ MIPS: .section .sbss
-//@ MIPS-NOT: .section
-//@ MIPS: V:
-//@ MIPS: .section .sdata
-//@ MIPS-NOT: .section
-//@ MIPS: W:
-//@ MIPS: .section .sbss
-//@ MIPS-NOT: .section
-//@ MIPS: X:
+// MIPS: .section .sdata
+// MIPS-NOT: .section
+// MIPS: U:
+// MIPS: .section .sbss
+// MIPS-NOT: .section
+// MIPS: V:
+// MIPS: .section .sdata
+// MIPS-NOT: .section
+// MIPS: W:
+// MIPS: .section .sbss
+// MIPS-NOT: .section
+// MIPS: X:
 
-//@ CHECK: .section .data.Y,
-//@ CHECK-NOT: .section
-//@ CHECK: Y:
-//@ CHECK: .section .bss.Z,
-//@ CHECK-NOT: .section
-//@ CHECK: Z:
+// CHECK: .section .data.Y,
+// CHECK-NOT: .section
+// CHECK: Y:
+// CHECK: .section .bss.Z,
+// CHECK-NOT: .section
+// CHECK: Z:
diff --git a/tests/codegen/addr-of-mutate.rs b/tests/codegen/addr-of-mutate.rs
index f10f01274b1..14bc4b8ab28 100644
--- a/tests/codegen/addr-of-mutate.rs
+++ b/tests/codegen/addr-of-mutate.rs
@@ -5,7 +5,7 @@
 // Test for the absence of `readonly` on the argument when it is mutated via `&raw const`.
 // See <https://github.com/rust-lang/rust/issues/111502>.
 
-// CHECK: i8 @foo(ptr noalias nocapture noundef align 1 dereferenceable(128) %x)
+// CHECK: i8 @foo(ptr noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x)
 #[no_mangle]
 pub fn foo(x: [u8; 128]) -> u8 {
     let ptr = core::ptr::addr_of!(x).cast_mut();
@@ -15,7 +15,7 @@ pub fn foo(x: [u8; 128]) -> u8 {
     x[0]
 }
 
-// CHECK: i1 @second(ptr noalias nocapture noundef align {{[0-9]+}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
+// CHECK: i1 @second(ptr noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
 #[no_mangle]
 pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
     let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut();
@@ -24,7 +24,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
 }
 
 // If going through a deref (and there are no other mutating accesses), then `readonly` is fine.
-// CHECK: i1 @third(ptr noalias nocapture noundef readonly align {{[0-9]+}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
+// CHECK: i1 @third(ptr noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
 #[no_mangle]
 pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
     let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut();
diff --git a/tests/codegen/asm/bpf-clobbers.rs b/tests/codegen/asm/bpf-clobbers.rs
new file mode 100644
index 00000000000..1117549b1ec
--- /dev/null
+++ b/tests/codegen/asm/bpf-clobbers.rs
@@ -0,0 +1,31 @@
+//@ add-core-stubs
+//@ compile-flags: --target bpfel-unknown-none
+//@ needs-llvm-components: bpf
+
+#![crate_type = "rlib"]
+#![feature(no_core, asm_experimental_arch)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+// CHECK-LABEL: @flags_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn flags_clobber() {
+    asm!("", options(nostack, nomem));
+}
+
+// CHECK-LABEL: @no_clobber
+// CHECK: call void asm sideeffect "", ""()
+#[no_mangle]
+pub unsafe fn no_clobber() {
+    asm!("", options(nostack, nomem, preserves_flags));
+}
+
+// CHECK-LABEL: @clobber_abi
+// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5}"()
+#[no_mangle]
+pub unsafe fn clobber_abi() {
+    asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
+}
diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs
index db76aae3dd0..b3a35cbf3b1 100644
--- a/tests/codegen/cast-target-abi.rs
+++ b/tests/codegen/cast-target-abi.rs
@@ -392,7 +392,7 @@ pub fn call_fiveu16s() {
 }
 
 // CHECK-LABEL: @return_fiveu16s
-// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] dereferenceable(10) [[RET_PTR:%.+]])
+// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}dereferenceable(10) [[RET_PTR:%.+]])
 #[no_mangle]
 pub fn return_fiveu16s() -> FiveU16s {
     // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs
index 514d35433e1..562a8e6c9e9 100644
--- a/tests/codegen/float/f128.rs
+++ b/tests/codegen/float/f128.rs
@@ -1,11 +1,15 @@
 // 32-bit x86 returns float types differently to avoid the x87 stack.
 // 32-bit systems will return 128bit values using a return area pointer.
-//@ revisions: x86 bit32 bit64
+// Emscripten aligns f128 to 8 bytes, not 16.
+//@ revisions: x86 bit32 bit64 emscripten
 //@[x86] only-x86
 //@[bit32] ignore-x86
+//@[bit32] ignore-emscripten
 //@[bit32] only-32bit
 //@[bit64] ignore-x86
+//@[bit64] ignore-emscripten
 //@[bit64] only-64bit
+//@[emscripten] only-emscripten
 
 // Verify that our intrinsics generate the correct LLVM calls for f128
 
@@ -59,6 +63,7 @@ pub fn f128_le(a: f128, b: f128) -> bool {
 // x86-LABEL: void @f128_neg({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_neg({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_neg(
+// emscripten-LABEL: void @f128_neg({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f128_neg(a: f128) -> f128 {
     // CHECK: fneg fp128
@@ -68,6 +73,7 @@ pub fn f128_neg(a: f128) -> f128 {
 // x86-LABEL: void @f128_add({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_add({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_add(
+// emscripten-LABEL: void @f128_add({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f128_add(a: f128, b: f128) -> f128 {
     // CHECK: fadd fp128 %{{.+}}, %{{.+}}
@@ -77,6 +83,7 @@ pub fn f128_add(a: f128, b: f128) -> f128 {
 // x86-LABEL: void @f128_sub({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_sub({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_sub(
+// emscripten-LABEL: void @f128_sub({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f128_sub(a: f128, b: f128) -> f128 {
     // CHECK: fsub fp128 %{{.+}}, %{{.+}}
@@ -86,6 +93,7 @@ pub fn f128_sub(a: f128, b: f128) -> f128 {
 // x86-LABEL: void @f128_mul({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_mul({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_mul(
+// emscripten-LABEL: void @f128_mul({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f128_mul(a: f128, b: f128) -> f128 {
     // CHECK: fmul fp128 %{{.+}}, %{{.+}}
@@ -95,6 +103,7 @@ pub fn f128_mul(a: f128, b: f128) -> f128 {
 // x86-LABEL: void @f128_div({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_div({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_div(
+// emscripten-LABEL: void @f128_div({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f128_div(a: f128, b: f128) -> f128 {
     // CHECK: fdiv fp128 %{{.+}}, %{{.+}}
@@ -104,6 +113,7 @@ pub fn f128_div(a: f128, b: f128) -> f128 {
 // x86-LABEL: void @f128_rem({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_rem({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_rem(
+// emscripten-LABEL: void @f128_rem({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f128_rem(a: f128, b: f128) -> f128 {
     // CHECK: frem fp128 %{{.+}}, %{{.+}}
@@ -164,6 +174,7 @@ pub fn f128_as_f16(a: f128) -> f16 {
 // x86-LABEL: i32 @f128_as_f32(
 // bit32-LABEL: float @f128_as_f32(
 // bit64-LABEL: float @f128_as_f32(
+// emscripten-LABEL: float @f128_as_f32(
 #[no_mangle]
 pub fn f128_as_f32(a: f128) -> f32 {
     // CHECK: fptrunc fp128 %{{.+}} to float
@@ -173,6 +184,7 @@ pub fn f128_as_f32(a: f128) -> f32 {
 // x86-LABEL: void @f128_as_f64(
 // bit32-LABEL: double @f128_as_f64(
 // bit64-LABEL: double @f128_as_f64(
+// emscripten-LABEL: double @f128_as_f64(
 #[no_mangle]
 pub fn f128_as_f64(a: f128) -> f64 {
     // CHECK: fptrunc fp128 %{{.+}} to double
@@ -182,17 +194,20 @@ pub fn f128_as_f64(a: f128) -> f64 {
 // x86-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f128_as_self(
+// emscripten-LABEL: void @f128_as_self({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f128_as_self(a: f128) -> f128 {
     // x86: store fp128 %a, ptr %_0, align 16
     // bit32: store fp128 %a, ptr %_0, align 16
     // bit64: ret fp128 %{{.+}}
+    // emscripten: store fp128 %a, ptr %_0, align 8
     a as f128
 }
 
 // x86-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f16_as_f128(
+// emscripten-LABEL: void @f16_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f16_as_f128(a: f16) -> f128 {
     // CHECK: fpext half %{{.+}} to fp128
@@ -202,6 +217,7 @@ pub fn f16_as_f128(a: f16) -> f128 {
 // x86-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f32_as_f128(
+// emscripten-LABEL: void @f32_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f32_as_f128(a: f32) -> f128 {
     // CHECK: fpext float %{{.+}} to fp128
@@ -211,6 +227,7 @@ pub fn f32_as_f128(a: f32) -> f128 {
 // x86-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @f64_as_f128(
+// emscripten-LABEL: void @f64_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f64_as_f128(a: f64) -> f128 {
     // CHECK: fpext double %{{.+}} to fp128
@@ -249,6 +266,7 @@ pub fn f128_as_u64(a: f128) -> u64 {
 // x86-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
 // bit64-LABEL: i128 @f128_as_u128(
+// emscripten-LABEL: void @f128_as_u128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f128_as_u128(a: f128) -> u128 {
     // CHECK: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}})
@@ -285,6 +303,7 @@ pub fn f128_as_i64(a: f128) -> i64 {
 // x86-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
 // bit64-LABEL: i128 @f128_as_i128(
+// emscripten-LABEL: void @f128_as_i128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn f128_as_i128(a: f128) -> i128 {
     // CHECK: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}})
@@ -296,6 +315,7 @@ pub fn f128_as_i128(a: f128) -> i128 {
 // x86-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u8_as_f128(
+// emscripten-LABEL: void @u8_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn u8_as_f128(a: u8) -> f128 {
     // CHECK: uitofp i8 %{{.+}} to fp128
@@ -305,6 +325,7 @@ pub fn u8_as_f128(a: u8) -> f128 {
 // x86-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u16_as_f128(
+// emscripten-LABEL: void @u16_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn u16_as_f128(a: u16) -> f128 {
     // CHECK: uitofp i16 %{{.+}} to fp128
@@ -314,6 +335,7 @@ pub fn u16_as_f128(a: u16) -> f128 {
 // x86-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u32_as_f128(
+// emscripten-LABEL: void @u32_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn u32_as_f128(a: u32) -> f128 {
     // CHECK: uitofp i32 %{{.+}} to fp128
@@ -323,6 +345,7 @@ pub fn u32_as_f128(a: u32) -> f128 {
 // x86-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u64_as_f128(
+// emscripten-LABEL: void @u64_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn u64_as_f128(a: u64) -> f128 {
     // CHECK: uitofp i64 %{{.+}} to fp128
@@ -332,6 +355,7 @@ pub fn u64_as_f128(a: u64) -> f128 {
 // x86-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @u128_as_f128(
+// emscripten-LABEL: void @u128_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn u128_as_f128(a: u128) -> f128 {
     // CHECK: uitofp i128 %{{.+}} to fp128
@@ -341,6 +365,7 @@ pub fn u128_as_f128(a: u128) -> f128 {
 // x86-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i8_as_f128(
+// emscripten-LABEL: void @i8_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn i8_as_f128(a: i8) -> f128 {
     // CHECK: sitofp i8 %{{.+}} to fp128
@@ -350,6 +375,7 @@ pub fn i8_as_f128(a: i8) -> f128 {
 // x86-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i16_as_f128(
+// emscripten-LABEL: void @i16_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn i16_as_f128(a: i16) -> f128 {
     // CHECK: sitofp i16 %{{.+}} to fp128
@@ -359,6 +385,7 @@ pub fn i16_as_f128(a: i16) -> f128 {
 // x86-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i32_as_f128(
+// emscripten-LABEL: void @i32_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn i32_as_f128(a: i32) -> f128 {
     // CHECK: sitofp i32 %{{.+}} to fp128
@@ -368,6 +395,7 @@ pub fn i32_as_f128(a: i32) -> f128 {
 // x86-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i64_as_f128(
+// emscripten-LABEL: void @i64_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn i64_as_f128(a: i64) -> f128 {
     // CHECK: sitofp i64 %{{.+}} to fp128
@@ -377,6 +405,7 @@ pub fn i64_as_f128(a: i64) -> f128 {
 // x86-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
 // bit32-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
 // bit64-LABEL: fp128 @i128_as_f128(
+// emscripten-LABEL: void @i128_as_f128({{.*}}sret([16 x i8])
 #[no_mangle]
 pub fn i128_as_f128(a: i128) -> f128 {
     // CHECK: sitofp i128 %{{.+}} to fp128
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index 503799d3ed2..1a211dfe096 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -135,7 +135,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {}
 #[no_mangle]
 pub fn notunpin_borrow(_: &NotUnpin) {}
 
-// CHECK: @indirect_struct(ptr noalias nocapture noundef readonly align 4 dereferenceable(32) %_1)
+// CHECK: @indirect_struct(ptr noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {}
 
@@ -198,7 +198,7 @@ pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
     x
 }
 
-// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias nocapture noundef{{( writable)?}} sret([32 x i8]) align 4 dereferenceable(32){{( %_0)?}})
+// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}})
 #[no_mangle]
 pub fn struct_return() -> S {
     S { _field: [0, 0, 0, 0, 0, 0, 0, 0] }
diff --git a/tests/codegen/i128-x86-align.rs b/tests/codegen/i128-x86-align.rs
index 6b1da445c40..ac101b72513 100644
--- a/tests/codegen/i128-x86-align.rs
+++ b/tests/codegen/i128-x86-align.rs
@@ -19,8 +19,10 @@ pub struct ScalarPair {
 #[no_mangle]
 pub fn load(x: &ScalarPair) -> ScalarPair {
     // CHECK-LABEL: @load(
-    // CHECK-SAME: sret([32 x i8]) align 16 dereferenceable(32) %_0,
-    // CHECK-SAME: align 16 dereferenceable(32) %x
+    // CHECK-SAME: sret([32 x i8]) align 16
+    // CHECK-SAME: dereferenceable(32) %_0,
+    // CHECK-SAME: align 16
+    // CHECK-SAME: dereferenceable(32) %x
     // CHECK:      [[A:%.*]] = load i32, ptr %x, align 16
     // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16
     // CHECK-NEXT: [[B:%.*]] = load i128, ptr [[GEP]], align 16
@@ -34,7 +36,8 @@ pub fn load(x: &ScalarPair) -> ScalarPair {
 #[no_mangle]
 pub fn store(x: &mut ScalarPair) {
     // CHECK-LABEL: @store(
-    // CHECK-SAME: align 16 dereferenceable(32) %x
+    // CHECK-SAME: align 16
+    // CHECK-SAME: dereferenceable(32) %x
     // CHECK:      store i32 1, ptr %x, align 16
     // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16
     // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16
@@ -55,8 +58,10 @@ pub fn alloca() {
 #[no_mangle]
 pub fn load_volatile(x: &ScalarPair) -> ScalarPair {
     // CHECK-LABEL: @load_volatile(
-    // CHECK-SAME: sret([32 x i8]) align 16 dereferenceable(32) %_0,
-    // CHECK-SAME: align 16 dereferenceable(32) %x
+    // CHECK-SAME: sret([32 x i8]) align 16
+    // CHECK-SAME: dereferenceable(32) %_0,
+    // CHECK-SAME: align 16
+    // CHECK-SAME: dereferenceable(32) %x
     // CHECK:      [[LOAD:%.*]] = load volatile %ScalarPair, ptr %x, align 16
     // CHECK-NEXT: store %ScalarPair [[LOAD]], ptr %_0, align 16
     // CHECK-NEXT: ret void
@@ -66,7 +71,8 @@ pub fn load_volatile(x: &ScalarPair) -> ScalarPair {
 #[no_mangle]
 pub fn transmute(x: ScalarPair) -> (std::mem::MaybeUninit<i128>, i128) {
     // CHECK-LABEL: @transmute(
-    // CHECK-SAME:  sret([32 x i8]) align 16 dereferenceable(32) %_0,
+    // CHECK-SAME:  sret([32 x i8]) align 16
+    // CHECK-SAME:  dereferenceable(32) %_0,
     // CHECK-SAME:  i32 noundef %x.0, i128 noundef %x.1
     // CHECK:       store i32 %x.0, ptr %_0, align 16
     // CHECK-NEXT:  [[GEP:%.*]] = getelementptr inbounds i8, ptr %_0, i64 16
@@ -86,7 +92,8 @@ pub struct Struct {
 #[no_mangle]
 pub fn store_struct(x: &mut Struct) {
     // CHECK-LABEL: @store_struct(
-    // CHECK-SAME: align 16 dereferenceable(32) %x
+    // CHECK-SAME: align 16
+    // CHECK-SAME: dereferenceable(32) %x
     // CHECK:      [[TMP:%.*]] = alloca [32 x i8], align 16
     // CHECK:      store i32 1, ptr [[TMP]], align 16
     // CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 4
diff --git a/tests/codegen/issues/issue-136329-optnone-noinline.rs b/tests/codegen/issues/issue-136329-optnone-noinline.rs
new file mode 100644
index 00000000000..57c9e47a499
--- /dev/null
+++ b/tests/codegen/issues/issue-136329-optnone-noinline.rs
@@ -0,0 +1,21 @@
+//! Ensure that `#[optimize(none)]` functions are never inlined
+
+//@ compile-flags: -Copt-level=3
+
+#![feature(optimize_attribute)]
+
+#[optimize(none)]
+pub fn foo() {
+    let _x = 123;
+}
+
+// CHECK-LABEL: define{{.*}}void @bar
+// CHECK: start:
+// CHECK: {{.*}}call {{.*}}void
+// CHECK: ret void
+#[no_mangle]
+pub fn bar() {
+    foo();
+}
+
+fn main() {}
diff --git a/tests/codegen/lib-optimizations/slice_rotate.rs b/tests/codegen/lib-optimizations/slice_rotate.rs
new file mode 100644
index 00000000000..d0a7b328d18
--- /dev/null
+++ b/tests/codegen/lib-optimizations/slice_rotate.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -O
+
+#![crate_type = "lib"]
+
+// Ensure that the simple case of rotating by a constant 1 optimizes to the obvious thing
+
+// CHECK-LABEL: @rotate_left_by_one
+#[no_mangle]
+pub fn rotate_left_by_one(slice: &mut [i32]) {
+    // CHECK-NOT: phi
+    // CHECK-NOT: call
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: getelementptr
+    // CHECK: %[[END:.+]] = getelementptr
+    // CHECK-NEXT: %[[DIM:.+]] = getelementptr
+    // CHECK-NEXT: %[[LAST:.+]] = load
+    // CHECK-NEXT: %[[FIRST:.+]] = shl
+    // CHECK-NEXT: call void @llvm.memmove
+    // CHECK-NEXT: store i32 %[[LAST]], ptr %[[DIM:.+]]
+    // CHECK-NOT: phi
+    // CHECK-NOT: call
+    // CHECK-NOT: load
+    // CHECK-NOT: store
+    // CHECK-NOT: getelementptr
+    // CHECK: ret void
+    if !slice.is_empty() {
+        slice.rotate_left(1);
+    }
+}
diff --git a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs
index cba1a980caa..b147d01b38e 100644
--- a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs
+++ b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs
@@ -259,11 +259,11 @@ pub struct IntDoubleInt {
     c: i32,
 }
 
-// CHECK: define void @f_int_double_int_s_arg(ptr noalias nocapture noundef align 8 dereferenceable(24) %a)
+// CHECK: define void @f_int_double_int_s_arg(ptr noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a)
 #[no_mangle]
 pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {}
 
-// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias nocapture noundef{{( writable)?}} sret([24 x i8]) align 8 dereferenceable(24) %_0)
+// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(none\))?}} dereferenceable(24) %_0)
 #[no_mangle]
 pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt {
     IntDoubleInt { a: 1, b: 2., c: 3 }
diff --git a/tests/codegen/packed.rs b/tests/codegen/packed.rs
index 790d618b2ea..66df978d48c 100644
--- a/tests/codegen/packed.rs
+++ b/tests/codegen/packed.rs
@@ -52,7 +52,7 @@ pub struct BigPacked2 {
 #[no_mangle]
 pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
     // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8]
-    // CHECK: call void %{{.*}}(ptr noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
+    // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
     // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
     // check that calls whose destination is a field of a packed struct
     // go through an alloca rather than calling the function with an
@@ -64,7 +64,7 @@ pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
 #[no_mangle]
 pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 {
     // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8]
-    // CHECK: call void %{{.*}}(ptr noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
+    // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
     // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
     // check that calls whose destination is a field of a packed struct
     // go through an alloca rather than calling the function with an
diff --git a/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs
index bcd9b0eae71..c14d5c01450 100644
--- a/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs
+++ b/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs
@@ -263,7 +263,7 @@ pub struct IntDoubleInt {
 #[no_mangle]
 pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {}
 
-// CHECK: define void @f_ret_int_double_int_s(ptr {{.*}} sret([24 x i8]) align 8 dereferenceable(24) %_0)
+// CHECK: define void @f_ret_int_double_int_s(ptr {{.*}} sret([24 x i8]) align 8 {{.*}}dereferenceable(24) %_0)
 #[no_mangle]
 pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt {
     IntDoubleInt { a: 1, b: 2., c: 3 }
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
index 605a0d520a7..7f99f695bf4 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
@@ -23,7 +23,7 @@ extern "rust-intrinsic" {
 #[no_mangle]
 pub unsafe fn gather_f32x2(pointers: Vec2<*const f32>, mask: Vec2<i32>,
                            values: Vec2<f32>) -> Vec2<f32> {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}})
     simd_gather(values, pointers, mask)
@@ -33,7 +33,7 @@ pub unsafe fn gather_f32x2(pointers: Vec2<*const f32>, mask: Vec2<i32>,
 #[no_mangle]
 pub unsafe fn gather_pf32x2(pointers: Vec2<*const *const f32>, mask: Vec2<i32>,
                            values: Vec2<*const f32>) -> Vec2<*const f32> {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call <2 x ptr> @llvm.masked.gather.v2p0.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x ptr> {{.*}})
     simd_gather(values, pointers, mask)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
index 015f6fd9cef..7f46630e920 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
@@ -21,7 +21,7 @@ extern "rust-intrinsic" {
 #[no_mangle]
 pub unsafe fn load_f32x2(mask: Vec2<i32>, pointer: *const f32,
                          values: Vec2<f32>) -> Vec2<f32> {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}})
     simd_masked_load(mask, pointer, values)
@@ -31,7 +31,7 @@ pub unsafe fn load_f32x2(mask: Vec2<i32>, pointer: *const f32,
 #[no_mangle]
 pub unsafe fn load_pf32x4(mask: Vec4<i32>, pointer: *const *const f32,
                           values: Vec4<*const f32>) -> Vec4<*const f32> {
-    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, <i32 31, i32 31, i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
     // CHECK: call <4 x ptr> @llvm.masked.load.v4p0.p0(ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]], <4 x ptr> {{.*}})
     simd_masked_load(mask, pointer, values)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
index 471a4bea181..0d43234f1e2 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
@@ -20,7 +20,7 @@ extern "rust-intrinsic" {
 // CHECK-LABEL: @store_f32x2
 #[no_mangle]
 pub unsafe fn store_f32x2(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>) {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]])
     simd_masked_store(mask, pointer, values)
@@ -29,7 +29,7 @@ pub unsafe fn store_f32x2(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>)
 // CHECK-LABEL: @store_pf32x4
 #[no_mangle]
 pub unsafe fn store_pf32x4(mask: Vec4<i32>, pointer: *mut *const f32, values: Vec4<*const f32>) {
-    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, <i32 31, i32 31, i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
     // CHECK: call void @llvm.masked.store.v4p0.p0(<4 x ptr> {{.*}}, ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]])
     simd_masked_store(mask, pointer, values)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
index 1c42b2534d8..ef7827bd96f 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
@@ -23,7 +23,7 @@ extern "rust-intrinsic" {
 #[no_mangle]
 pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2<i32>,
                             values: Vec2<f32>) {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]]
     simd_scatter(values, pointers, mask)
@@ -34,7 +34,7 @@ pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2<i32>,
 #[no_mangle]
 pub unsafe fn scatter_pf32x2(pointers: Vec2<*mut *const f32>, mask: Vec2<i32>,
                              values: Vec2<*const f32>) {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call void @llvm.masked.scatter.v2p0.v2p0(<2 x ptr> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]]
     simd_scatter(values, pointers, mask)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
index a73593160f2..33ed2b437f9 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
@@ -29,7 +29,7 @@ extern "rust-intrinsic" {
 // CHECK-LABEL: @select_m8
 #[no_mangle]
 pub unsafe fn select_m8(m: b8x4, a: f32x4, b: f32x4) -> f32x4 {
-    // CHECK: [[A:%[0-9]+]] = lshr <4 x i8> %{{.*}}, <i8 7, i8 7, i8 7, i8 7>
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i8> %{{.*}}, {{<i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <4 x i8> [[A]] to <4 x i1>
     // CHECK: select <4 x i1> [[B]]
     simd_select(m, a, b)
@@ -38,7 +38,7 @@ pub unsafe fn select_m8(m: b8x4, a: f32x4, b: f32x4) -> f32x4 {
 // CHECK-LABEL: @select_m32
 #[no_mangle]
 pub unsafe fn select_m32(m: i32x4, a: f32x4, b: f32x4) -> f32x4 {
-    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, <i32 31, i32 31, i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
     // CHECK: select <4 x i1> [[B]]
     simd_select(m, a, b)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs
index 4df246c2f5c..92067db9b15 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs
@@ -27,7 +27,7 @@ extern "rust-intrinsic" {
 // CHECK-LABEL: @reduce_any_32x2
 #[no_mangle]
 pub unsafe fn reduce_any_32x2(x: mask32x2) -> bool {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[B]])
     // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
@@ -37,7 +37,7 @@ pub unsafe fn reduce_any_32x2(x: mask32x2) -> bool {
 // CHECK-LABEL: @reduce_all_32x2
 #[no_mangle]
 pub unsafe fn reduce_all_32x2(x: mask32x2) -> bool {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v2i1(<2 x i1> [[B]])
     // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
@@ -47,7 +47,7 @@ pub unsafe fn reduce_all_32x2(x: mask32x2) -> bool {
 // CHECK-LABEL: @reduce_any_8x16
 #[no_mangle]
 pub unsafe fn reduce_any_8x16(x: mask8x16) -> bool {
-    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{<i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
     // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v16i1(<16 x i1> [[B]])
     // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
@@ -57,7 +57,7 @@ pub unsafe fn reduce_any_8x16(x: mask8x16) -> bool {
 // CHECK-LABEL: @reduce_all_8x16
 #[no_mangle]
 pub unsafe fn reduce_all_8x16(x: mask8x16) -> bool {
-    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{<i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
     // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v16i1(<16 x i1> [[B]])
     // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
diff --git a/tests/codegen/wasm_exceptions.rs b/tests/codegen/wasm_exceptions.rs
index 719499dd8ea..07b8ae6e9d7 100644
--- a/tests/codegen/wasm_exceptions.rs
+++ b/tests/codegen/wasm_exceptions.rs
@@ -1,5 +1,5 @@
 //@ only-wasm32
-//@ compile-flags: -C panic=unwind
+//@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh
 
 #![crate_type = "lib"]
 #![feature(core_intrinsics)]
diff --git a/tests/crashes/131102.rs b/tests/crashes/131102.rs
deleted file mode 100644
index 12b35f8d1b2..00000000000
--- a/tests/crashes/131102.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ known-bug: #131102
-pub struct Blorb<const N: u16>([String; N]);
-pub struct Wrap(Blorb<0>);
-pub const fn i(_: Wrap) {}
diff --git a/tests/crashes/131103.rs b/tests/crashes/131103.rs
deleted file mode 100644
index 70193e8b3bd..00000000000
--- a/tests/crashes/131103.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ known-bug: #131103
-struct Struct<const N: i128>(pub [u8; N]);
-
-pub fn function(value: Struct<3>) -> u8 {
-    value.0[0]
-}
diff --git a/tests/crashes/135210.rs b/tests/crashes/135210.rs
deleted file mode 100644
index acb61e21090..00000000000
--- a/tests/crashes/135210.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #135210
-
-#![feature(const_trait_impl)]
-const _: fn(&String) = |s| {
-    &*s as &str;
-};
-
-fn main() {}
diff --git a/tests/mir-opt/null_check_references.rs b/tests/mir-opt/null_check_references.rs
new file mode 100644
index 00000000000..85f98865646
--- /dev/null
+++ b/tests/mir-opt/null_check_references.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -C debug-assertions
+
+struct Null {
+    a: u32,
+}
+
+fn main() {
+    // CHECK-LABEL: fn main(
+    // CHECK-NOT: {{assert.*}}
+    let val: u32 = 42;
+    let val_ref: &u32 = &val;
+    let _access1: &u32 = &*val_ref;
+
+    let val = Null { a: 42 };
+    let _access2: &u32 = &val.a;
+}
diff --git a/tests/mir-opt/pattern_types.main.PreCodegen.after.mir b/tests/mir-opt/pattern_types.main.PreCodegen.after.mir
new file mode 100644
index 00000000000..8c99902f9b8
--- /dev/null
+++ b/tests/mir-opt/pattern_types.main.PreCodegen.after.mir
@@ -0,0 +1,15 @@
+// MIR for `main` after PreCodegen
+
+fn main() -> () {
+    let mut _0: ();
+    scope 1 {
+        debug x => const 2_u32 is 1..=;
+        scope 2 {
+            debug y => const 0_u32 is 1..=;
+        }
+    }
+
+    bb0: {
+        return;
+    }
+}
diff --git a/tests/mir-opt/pattern_types.rs b/tests/mir-opt/pattern_types.rs
new file mode 100644
index 00000000000..217c64b90cb
--- /dev/null
+++ b/tests/mir-opt/pattern_types.rs
@@ -0,0 +1,12 @@
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+// EMIT_MIR pattern_types.main.PreCodegen.after.mir
+fn main() {
+    // CHECK: debug x => const 2_u32 is 1..=
+    let x: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(2) };
+    // CHECK: debug y => const 0_u32 is 1..=
+    let y: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) };
+}
diff --git a/tests/run-make/symbol-mangling-hashed/Makefile b/tests/run-make/symbol-mangling-hashed/Makefile
deleted file mode 100644
index c95036ead95..00000000000
--- a/tests/run-make/symbol-mangling-hashed/Makefile
+++ /dev/null
@@ -1,48 +0,0 @@
-include ../tools.mk
-
-# ignore-cross-compile
-# only-linux
-# only-x86_64
-
-NM=nm -D
-RLIB_NAME=liba_rlib.rlib
-DYLIB_NAME=liba_dylib.so
-SO_NAME=libb_dylib.so
-BIN_NAME=b_bin
-
-ifeq ($(UNAME),Darwin)
-NM=nm -gU
-RLIB_NAME=liba_rlib.rlib
-DYLIB_NAME=liba_dylib.dylib
-SO_NAME=libb_dylib.dylib
-BIN_NAME=b_bin
-endif
-
-ifdef IS_WINDOWS
-NM=nm -g
-RLIB_NAME=liba_rlib.dll.a
-DYLIB_NAME=liba_dylib.dll
-SO_NAME=libb_dylib.dll
-BIN_NAME=b_bin.exe
-endif
-
-all:
-	$(RUSTC) -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=hashed -C metadata=foo a_dylib.rs
-	$(RUSTC) -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=hashed -C metadata=bar a_rlib.rs
-	$(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_dylib.rs
-	$(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_bin.rs
-
-    # Check hashed symbol name
-
-	[ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep -c hello)" -eq "0" ]
-	[ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep _RNxC7a_dylib | grep -c ' T ')" -eq "2" ]
-
-	[ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep b_dylib | grep -c hello)" -eq "1" ]
-	[ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep _RNxC6a_rlib | grep -c ' T ')" -eq "2" ]
-	[ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep _RNxC7a_dylib | grep -c ' U ')" -eq "1" ]
-
-	[ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep _RNxC6a_rlib | grep -c ' U ')" -eq "1" ]
-	[ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep _RNxC7a_dylib | grep -c ' U ')" -eq "1" ]
-	[ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep b_dylib | grep hello | grep -c ' U ')" -eq "1" ]
-
-	$(call RUN,$(BIN_NAME))
diff --git a/tests/run-make/symbol-mangling-hashed/b_bin.rs b/tests/run-make/symbol-mangling-hashed/b_bin.rs
deleted file mode 100644
index 8ee7fecda62..00000000000
--- a/tests/run-make/symbol-mangling-hashed/b_bin.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-extern crate a_dylib;
-extern crate a_rlib;
-extern crate b_dylib;
-
-fn main() {
-    a_rlib::hello();
-    a_dylib::hello();
-    b_dylib::hello();
-}
diff --git a/tests/run-make/symbol-mangling-hashed/b_dylib.rs b/tests/run-make/symbol-mangling-hashed/b_dylib.rs
deleted file mode 100644
index 3252c9c75c2..00000000000
--- a/tests/run-make/symbol-mangling-hashed/b_dylib.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![crate_type = "dylib"]
-
-extern crate a_dylib;
-extern crate a_rlib;
-
-pub fn hello() {
-    a_rlib::hello();
-    a_dylib::hello();
-}
diff --git a/tests/run-make/symbol-mangling-hashed/default_bin.rs b/tests/run-make/symbol-mangling-hashed/default_bin.rs
new file mode 100644
index 00000000000..387596705c3
--- /dev/null
+++ b/tests/run-make/symbol-mangling-hashed/default_bin.rs
@@ -0,0 +1,9 @@
+extern crate default_dylib;
+extern crate hashed_dylib;
+extern crate hashed_rlib;
+
+fn main() {
+    hashed_rlib::hrhello();
+    hashed_dylib::hdhello();
+    default_dylib::ddhello();
+}
diff --git a/tests/run-make/symbol-mangling-hashed/default_dylib.rs b/tests/run-make/symbol-mangling-hashed/default_dylib.rs
new file mode 100644
index 00000000000..986d1c7b74d
--- /dev/null
+++ b/tests/run-make/symbol-mangling-hashed/default_dylib.rs
@@ -0,0 +1,9 @@
+#![crate_type = "dylib"]
+
+extern crate hashed_dylib;
+extern crate hashed_rlib;
+
+pub fn ddhello() {
+    hashed_rlib::hrhello();
+    hashed_dylib::hdhello();
+}
diff --git a/tests/run-make/symbol-mangling-hashed/a_dylib.rs b/tests/run-make/symbol-mangling-hashed/hashed_dylib.rs
index 49d65b72cac..fbb7cba43e0 100644
--- a/tests/run-make/symbol-mangling-hashed/a_dylib.rs
+++ b/tests/run-make/symbol-mangling-hashed/hashed_dylib.rs
@@ -1,4 +1,4 @@
 #![crate_type = "dylib"]
-pub fn hello() {
+pub fn hdhello() {
     println!("hello dylib");
 }
diff --git a/tests/run-make/symbol-mangling-hashed/a_rlib.rs b/tests/run-make/symbol-mangling-hashed/hashed_rlib.rs
index 71e44ccc200..048e67784d2 100644
--- a/tests/run-make/symbol-mangling-hashed/a_rlib.rs
+++ b/tests/run-make/symbol-mangling-hashed/hashed_rlib.rs
@@ -1,5 +1,5 @@
 #![crate_type = "rlib"]
 
-pub fn hello() {
+pub fn hrhello() {
     println!("hello rlib");
 }
diff --git a/tests/run-make/symbol-mangling-hashed/rmake.rs b/tests/run-make/symbol-mangling-hashed/rmake.rs
new file mode 100644
index 00000000000..136e6b9fa3a
--- /dev/null
+++ b/tests/run-make/symbol-mangling-hashed/rmake.rs
@@ -0,0 +1,108 @@
+// ignore-tidy-linelength
+//! Basic smoke test for the unstable option `-C symbol_mangling_version=hashed` which aims to
+//! replace full symbol mangling names based on hash digests to shorten symbol name lengths in
+//! dylibs for space savings.
+//!
+//! # References
+//!
+//! - MCP #705: Provide option to shorten symbol names by replacing them with a digest:
+//!   <https://github.com/rust-lang/compiler-team/issues/705>.
+//! - Implementation PR: <https://github.com/rust-lang/rust/pull/118636>.
+//! - PE format: <https://learn.microsoft.com/en-us/windows/win32/debug/pe-format>.
+
+//@ ignore-cross-compile
+
+#![deny(warnings)]
+
+use run_make_support::symbols::exported_dynamic_symbol_names;
+use run_make_support::{bin_name, cwd, dynamic_lib_name, is_darwin, object, rfs, run, rustc};
+
+macro_rules! adjust_symbol_prefix {
+    ($name:literal) => {
+        if is_darwin() { concat!("_", $name) } else { $name }
+    };
+}
+
+fn main() {
+    rustc()
+        .input("hashed_dylib.rs")
+        .prefer_dynamic()
+        .arg("-Zunstable-options")
+        .symbol_mangling_version("hashed")
+        .metadata("foo")
+        .run();
+
+    rustc()
+        .input("hashed_rlib.rs")
+        .prefer_dynamic()
+        .arg("-Zunstable-options")
+        .symbol_mangling_version("hashed")
+        .metadata("bar")
+        .run();
+
+    rustc().input("default_dylib.rs").library_search_path(cwd()).prefer_dynamic().run();
+    rustc().input("default_bin.rs").library_search_path(cwd()).prefer_dynamic().run();
+
+    {
+        // Check hashed symbol name
+
+        let dylib_filename = dynamic_lib_name("hashed_dylib");
+        println!("checking dylib `{dylib_filename}`");
+
+        let dylib_blob = rfs::read(&dylib_filename);
+        let dylib_file = object::File::parse(&*dylib_blob)
+            .unwrap_or_else(|e| panic!("failed to parse `{dylib_filename}`: {e}"));
+
+        let dynamic_symbols = exported_dynamic_symbol_names(&dylib_file);
+
+        if dynamic_symbols.iter().filter(|sym| sym.contains("hdhello")).count() != 0 {
+            eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols);
+            panic!("expected no occurrence of `hdhello`");
+        }
+
+        let expected_prefix = adjust_symbol_prefix!("_RNxC12hashed_dylib");
+        if dynamic_symbols.iter().filter(|sym| sym.starts_with(expected_prefix)).count() != 2 {
+            eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols);
+            panic!("expected two dynamic symbols starting with `{expected_prefix}`");
+        }
+    }
+
+    {
+        let dylib_filename = dynamic_lib_name("default_dylib");
+        println!("checking so `{dylib_filename}`");
+
+        let dylib_blob = rfs::read(&dylib_filename);
+        let dylib_file = object::File::parse(&*dylib_blob)
+            .unwrap_or_else(|e| panic!("failed to parse `{dylib_filename}`: {e}"));
+
+        let dynamic_symbols = exported_dynamic_symbol_names(&dylib_file);
+
+        if dynamic_symbols
+            .iter()
+            .filter(|sym| sym.contains("default_dylib") && sym.contains("ddhello"))
+            .count()
+            != 1
+        {
+            eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols);
+            panic!("expected one occurrence of mangled `ddhello`");
+        }
+
+        let expected_rlib_prefix = adjust_symbol_prefix!("_RNxC11hashed_rlib");
+        if dynamic_symbols.iter().filter(|sym| sym.starts_with(expected_rlib_prefix)).count() != 2 {
+            eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols);
+            panic!("expected two exported symbols starting with `{expected_rlib_prefix}`");
+        }
+
+        let expected_dylib_prefix = adjust_symbol_prefix!("_RNxC12hashed_dylib");
+        if dynamic_symbols.iter().any(|sym| sym.starts_with("_RNxC12hashed_dylib")) {
+            eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols);
+            panic!("did not expect any symbols starting with `{expected_dylib_prefix}`");
+        }
+    }
+
+    // Check that the final binary can be run.
+    {
+        let bin_filename = bin_name("default_bin");
+        run(&bin_filename);
+    }
+}
diff --git a/tests/run-make/target-specs/require-explicit-cpu.json b/tests/run-make/target-specs/require-explicit-cpu.json
new file mode 100644
index 00000000000..5cbb9573b3f
--- /dev/null
+++ b/tests/run-make/target-specs/require-explicit-cpu.json
@@ -0,0 +1,11 @@
+{
+    "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128",
+    "linker-flavor": "gcc",
+    "llvm-target": "i686-unknown-linux-gnu",
+    "target-endian": "little",
+    "target-pointer-width": "32",
+    "target-c-int-width": "32",
+    "arch": "x86",
+    "os": "linux",
+    "need-explicit-cpu": true
+}
diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs
index 79c888ab340..f36a5784c89 100644
--- a/tests/run-make/target-specs/rmake.rs
+++ b/tests/run-make/target-specs/rmake.rs
@@ -63,4 +63,17 @@ fn main() {
         .crate_type("lib")
         .run_fail()
         .assert_stderr_contains("data-layout for target");
+    rustc()
+        .input("foo.rs")
+        .target("require-explicit-cpu")
+        .crate_type("lib")
+        .run_fail()
+        .assert_stderr_contains("target requires explicitly specifying a cpu");
+    rustc()
+        .input("foo.rs")
+        .target("require-explicit-cpu")
+        .crate_type("lib")
+        .arg("-Ctarget-cpu=generic")
+        .run();
+    rustc().target("require-explicit-cpu").arg("--print=target-cpus").run();
 }
diff --git a/tests/run-make/translation/Makefile b/tests/run-make/translation/Makefile
deleted file mode 100644
index 07e0547cfa0..00000000000
--- a/tests/run-make/translation/Makefile
+++ /dev/null
@@ -1,78 +0,0 @@
-include ../tools.mk
-
-# This test uses `ln -s` rather than copying to save testing time, but its
-# usage doesn't work on Windows.
-# ignore-windows
-
-SYSROOT:=$(shell $(RUSTC) --print sysroot)
-FAKEROOT=$(TMPDIR)/fakeroot
-RUSTC_LOG:=rustc_error_messages
-export RUSTC_TRANSLATION_NO_DEBUG_ASSERT:=1
-
-all: normal custom missing broken sysroot sysroot-invalid sysroot-missing
-
-# Check that the test works normally, using the built-in fallback bundle.
-normal: test.rs
-	$(RUSTC) $< 2>&1 | $(CGREP) "struct literal body without path"
-
-# Check that a primary bundle can be loaded and will be preferentially used
-# where possible.
-custom: test.rs working.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | $(CGREP) "this is a test message"
-
-# Check that a primary bundle with a broken message (e.g. a interpolated
-# variable is missing) will use the fallback bundle.
-missing: test.rs missing.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | $(CGREP) "struct literal body without path"
-
-# Check that a primary bundle without the desired message will use the fallback
-# bundle.
-broken: test.rs broken.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | $(CGREP) "struct literal body without path"
-
-# Check that a locale can be loaded from the sysroot given a language
-# identifier by making a local copy of the sysroot and adding the custom locale
-# to it.
-sysroot: test.rs working.ftl
-	rm -rf $(FAKEROOT)
-	mkdir $(FAKEROOT)
-	ln -s $(SYSROOT)/* $(FAKEROOT)
-	rm -f $(FAKEROOT)/lib
-	mkdir $(FAKEROOT)/lib
-	ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib
-	rm -f $(FAKEROOT)/lib/rustlib
-	mkdir $(FAKEROOT)/lib/rustlib
-	ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib
-	rm -f $(FAKEROOT)/lib/rustlib/src
-	mkdir $(FAKEROOT)/lib/rustlib/src
-	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
-	# When download-rustc is enabled, `$(SYSROOT)` will have a share directory. Delete the link to it.
-	rm -f $(FAKEROOT)/share
-	mkdir -p $(FAKEROOT)/share/locale/zh-CN/
-	ln -s $(CURDIR)/working.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl
-	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "this is a test message"
-
-# Check that the compiler errors out when the sysroot requested cannot be
-# found. This test might start failing if there actually exists a Klingon
-# translation of rustc's error messages.
-sysroot-missing:
-	$(RUSTC) $< -Ztranslate-lang=tlh 2>&1 | $(CGREP) "missing locale directory"
-
-# Check that the compiler errors out when the directory for the locale in the
-# sysroot is actually a file.
-sysroot-invalid: test.rs working.ftl
-	rm -rf $(FAKEROOT)
-	mkdir $(FAKEROOT)
-	ln -s $(SYSROOT)/* $(FAKEROOT)
-	rm -f $(FAKEROOT)/lib
-	mkdir $(FAKEROOT)/lib
-	ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib
-	rm -f $(FAKEROOT)/lib/rustlib
-	mkdir $(FAKEROOT)/lib/rustlib
-	ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib
-	rm -f $(FAKEROOT)/lib/rustlib/src
-	mkdir $(FAKEROOT)/lib/rustlib/src
-	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
-	mkdir -p $(FAKEROOT)/share/locale
-	touch $(FAKEROOT)/share/locale/zh-CN
-	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "`\$sysroot/share/locales/\$locale` is not a directory"
diff --git a/tests/run-make/translation/rmake.rs b/tests/run-make/translation/rmake.rs
new file mode 100644
index 00000000000..86078888c2e
--- /dev/null
+++ b/tests/run-make/translation/rmake.rs
@@ -0,0 +1,194 @@
+//! Smoke test for the rustc diagnostics translation infrastructure.
+//!
+//! # References
+//!
+//! - Current tracking issue: <https://github.com/rust-lang/rust/issues/132181>.
+//! - Old tracking issue: <https://github.com/rust-lang/rust/issues/100717>
+//! - Initial translation infra implementation: <https://github.com/rust-lang/rust/pull/95512>.
+
+// This test uses symbolic links to stub out a fake sysroot to save testing time.
+//@ needs-symlink
+//@ needs-subprocess
+
+#![deny(warnings)]
+
+use std::path::{Path, PathBuf};
+
+use run_make_support::rustc::sysroot;
+use run_make_support::{cwd, rfs, run_in_tmpdir, rustc};
+
+fn main() {
+    builtin_fallback_bundle();
+    additional_primary_bundle();
+    missing_slug_prefers_fallback_bundle();
+    broken_primary_bundle_prefers_fallback_bundle();
+    locale_sysroot();
+    missing_sysroot();
+    file_sysroot();
+}
+
+/// Check that the test works normally, using the built-in fallback bundle.
+fn builtin_fallback_bundle() {
+    rustc().input("test.rs").run_fail().assert_stderr_contains("struct literal body without path");
+}
+
+/// Check that a primary bundle can be loaded and will be preferentially used where possible.
+fn additional_primary_bundle() {
+    rustc()
+        .input("test.rs")
+        .arg("-Ztranslate-additional-ftl=working.ftl")
+        .run_fail()
+        .assert_stderr_contains("this is a test message");
+}
+
+/// Check that a primary bundle without the desired message will use the fallback bundle.
+fn missing_slug_prefers_fallback_bundle() {
+    rustc()
+        .input("test.rs")
+        .arg("-Ztranslate-additional-ftl=missing.ftl")
+        .run_fail()
+        .assert_stderr_contains("struct literal body without path");
+}
+
+/// Check that a primary bundle with a broken message (e.g. an interpolated variable is not
+/// provided) will use the fallback bundle.
+fn broken_primary_bundle_prefers_fallback_bundle() {
+    // FIXME(#135817): as of the rmake.rs port, the compiler actually ICEs on the additional
+    // `broken.ftl`, even though the original intention seems to be that it should gracefully
+    // failover to the fallback bundle. On `aarch64-apple-darwin`, somehow it *doesn't* ICE.
+
+    rustc()
+        .env("RUSTC_ICE", "0") // disable ICE dump file, not needed
+        .input("test.rs")
+        .arg("-Ztranslate-additional-ftl=broken.ftl")
+        .run_fail();
+}
+
+#[track_caller]
+fn shallow_symlink_dir_entries(src_dir: &Path, dst_dir: &Path) {
+    for entry in rfs::read_dir(src_dir) {
+        let entry = entry.unwrap();
+        let src_entry_path = entry.path();
+        let src_filename = src_entry_path.file_name().unwrap();
+        let meta = rfs::symlink_metadata(&src_entry_path);
+        if meta.is_symlink() || meta.is_file() {
+            rfs::symlink_file(&src_entry_path, dst_dir.join(src_filename));
+        } else if meta.is_dir() {
+            rfs::symlink_dir(&src_entry_path, dst_dir.join(src_filename));
+        } else {
+            unreachable!()
+        }
+    }
+}
+
+#[track_caller]
+fn shallow_symlink_dir_entries_materialize_single_dir(
+    src_dir: &Path,
+    dst_dir: &Path,
+    dir_filename: &str,
+) {
+    shallow_symlink_dir_entries(src_dir, dst_dir);
+
+    let dst_symlink_meta = rfs::symlink_metadata(dst_dir.join(dir_filename));
+
+    if dst_symlink_meta.is_file() || dst_symlink_meta.is_dir() {
+        unreachable!();
+    }
+
+    #[cfg(windows)]
+    {
+        use std::os::windows::fs::FileTypeExt as _;
+        if dst_symlink_meta.file_type().is_symlink_file() {
+            rfs::remove_file(dst_dir.join(dir_filename));
+        } else if dst_symlink_meta.file_type().is_symlink_dir() {
+            rfs::remove_dir(dst_dir.join(dir_filename));
+        } else {
+            unreachable!();
+        }
+    }
+    #[cfg(not(windows))]
+    {
+        rfs::remove_file(dst_dir.join(dir_filename));
+    }
+
+    rfs::create_dir_all(dst_dir.join(dir_filename));
+}
+
+#[track_caller]
+fn setup_fakeroot_parents() -> PathBuf {
+    let sysroot = sysroot();
+    let fakeroot = cwd().join("fakeroot");
+    rfs::create_dir_all(&fakeroot);
+    shallow_symlink_dir_entries_materialize_single_dir(&sysroot, &fakeroot, "lib");
+    shallow_symlink_dir_entries_materialize_single_dir(
+        &sysroot.join("lib"),
+        &fakeroot.join("lib"),
+        "rustlib",
+    );
+    shallow_symlink_dir_entries_materialize_single_dir(
+        &sysroot.join("lib").join("rustlib"),
+        &fakeroot.join("lib").join("rustlib"),
+        "src",
+    );
+    shallow_symlink_dir_entries(
+        &sysroot.join("lib").join("rustlib").join("src"),
+        &fakeroot.join("lib").join("rustlib").join("src"),
+    );
+    fakeroot
+}
+
+/// Check that a locale can be loaded from the sysroot given a language identifier by making a local
+/// copy of the sysroot and adding the custom locale to it.
+fn locale_sysroot() {
+    run_in_tmpdir(|| {
+        let fakeroot = setup_fakeroot_parents();
+
+        // When download-rustc is enabled, real sysroot will have a share directory. Delete the link
+        // to it.
+        let _ = std::fs::remove_file(fakeroot.join("share"));
+
+        let fake_locale_path = fakeroot.join("share").join("locale").join("zh-CN");
+        rfs::create_dir_all(&fake_locale_path);
+        rfs::symlink_file(
+            cwd().join("working.ftl"),
+            fake_locale_path.join("basic-translation.ftl"),
+        );
+
+        rustc()
+            .env("RUSTC_ICE", "0")
+            .input("test.rs")
+            .sysroot(&fakeroot)
+            .arg("-Ztranslate-lang=zh-CN")
+            .run_fail()
+            .assert_stderr_contains("this is a test message");
+    });
+}
+
+/// Check that the compiler errors out when the sysroot requested cannot be found. This test might
+/// start failing if there actually exists a Klingon translation of rustc's error messages.
+fn missing_sysroot() {
+    run_in_tmpdir(|| {
+        rustc()
+            .input("test.rs")
+            .arg("-Ztranslate-lang=tlh")
+            .run_fail()
+            .assert_stderr_contains("missing locale directory");
+    });
+}
+
+/// Check that the compiler errors out when the directory for the locale in the sysroot is actually
+/// a file.
+fn file_sysroot() {
+    run_in_tmpdir(|| {
+        let fakeroot = setup_fakeroot_parents();
+        rfs::create_dir_all(fakeroot.join("share").join("locale"));
+        rfs::write(fakeroot.join("share").join("locale").join("zh-CN"), b"not a dir");
+
+        rustc()
+            .input("test.rs")
+            .sysroot(&fakeroot)
+            .arg("-Ztranslate-lang=zh-CN")
+            .run_fail()
+            .assert_stderr_contains("is not a directory");
+    });
+}
diff --git a/tests/rustdoc-gui/font-serif-change.goml b/tests/rustdoc-gui/font-serif-change.goml
new file mode 100644
index 00000000000..b14d5ae96f9
--- /dev/null
+++ b/tests/rustdoc-gui/font-serif-change.goml
@@ -0,0 +1,31 @@
+// Ensures that the font serif change is working as expected.
+go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
+
+// By default, it should be the serif fonts.
+store-value: (serif_font, '"Source Serif 4", NanumBarunGothic, serif')
+store-value: (serif_code_font, '"Source Code Pro", monospace')
+assert-css: ("body", {"font-family": |serif_font|})
+assert-css: ("p code", {"font-family": |serif_code_font|})
+
+// We now switch to the sans serif font
+click: "#settings-menu"
+wait-for: "#sans-serif-fonts"
+click: "#sans-serif-fonts"
+
+store-value: (font, '"Fira Sans", sans-serif')
+store-value: (code_font, '"Fira Mono", monospace')
+assert-css: ("body", {"font-family": |font|})
+assert-css: ("p code", {"font-family": |code_font|})
+
+// Reloading the page to ensure it is loaded correctly.
+reload:
+assert-css: ("body", {"font-family": |font|})
+assert-css: ("p code", {"font-family": |code_font|})
+
+// We switch back to the serif font
+click: "#settings-menu"
+wait-for: "#sans-serif-fonts"
+click: "#sans-serif-fonts"
+
+assert-css: ("body", {"font-family": |serif_font|})
+assert-css: ("p code", {"font-family": |serif_code_font|})
diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml
index 1d93c07f9ec..4ab5b83d7c4 100644
--- a/tests/rustdoc-gui/settings.goml
+++ b/tests/rustdoc-gui/settings.goml
@@ -257,15 +257,15 @@ assert-text: ("#preferred-light-theme .setting-radio-name", "Preferred light the
 // We now check that clicking on the toggles' text is like clicking on the checkbox.
 // To test it, we use the "Disable keyboard shortcuts".
 set-local-storage: {"rustdoc-disable-shortcuts": "false"}
-click: ".setting-line:last-child .setting-check span"
+click: "#disable-shortcuts"
 assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
 
 // We now check that focusing a toggle and pressing Space is like clicking on it.
 assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
-focus: ".setting-line:last-child .setting-check input"
+focus: "#disable-shortcuts"
 press-key: "Space"
 assert-local-storage: {"rustdoc-disable-shortcuts": "false"}
-focus: ".setting-line:last-child .setting-check input"
+focus: "#disable-shortcuts"
 press-key: "Space"
 assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
 
@@ -276,7 +276,7 @@ assert-false: "#help-button .popover"
 wait-for-css: ("#settings-menu .popover", {"display": "block"})
 
 // Now turn keyboard shortcuts back on, and see if they work.
-click: ".setting-line:last-child .setting-check span"
+click: "#disable-shortcuts"
 assert-local-storage: {"rustdoc-disable-shortcuts": "false"}
 press-key: "Escape"
 press-key: "?"
diff --git a/tests/rustdoc-ui/coverage/html.stderr b/tests/rustdoc-ui/coverage/html.stderr
index adca375d4bc..764179820c5 100644
--- a/tests/rustdoc-ui/coverage/html.stderr
+++ b/tests/rustdoc-ui/coverage/html.stderr
@@ -1,2 +1,2 @@
-error: html output format isn't supported for the --show-coverage option
+error: `--output-format=html` is not supported for the `--show-coverage` option
 
diff --git a/tests/rustdoc-ui/doctest-output.rs b/tests/rustdoc-ui/doctest-output.rs
new file mode 100644
index 00000000000..720f2952980
--- /dev/null
+++ b/tests/rustdoc-ui/doctest-output.rs
@@ -0,0 +1 @@
+//@ compile-flags:-Z unstable-options --show-coverage --output-format=doctest
diff --git a/tests/rustdoc-ui/doctest-output.stderr b/tests/rustdoc-ui/doctest-output.stderr
new file mode 100644
index 00000000000..20c618dc61b
--- /dev/null
+++ b/tests/rustdoc-ui/doctest-output.stderr
@@ -0,0 +1,2 @@
+error: `--output-format=doctest` is not supported for the `--show-coverage` option
+
diff --git a/tests/rustdoc-ui/extract-doctests.rs b/tests/rustdoc-ui/extract-doctests.rs
new file mode 100644
index 00000000000..06bd35969d0
--- /dev/null
+++ b/tests/rustdoc-ui/extract-doctests.rs
@@ -0,0 +1,15 @@
+// Test to ensure that it generates expected output for `--output-format=doctest` command-line
+// flag.
+
+//@ compile-flags:-Z unstable-options --output-format=doctest
+//@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR"
+//@ check-pass
+
+//! ```ignore (checking attributes)
+//! let x = 12;
+//! let y = 14;
+//! ```
+//!
+//! ```edition2018,compile_fail
+//! let
+//! ```
diff --git a/tests/rustdoc-ui/extract-doctests.stdout b/tests/rustdoc-ui/extract-doctests.stdout
new file mode 100644
index 00000000000..fa8604cae94
--- /dev/null
+++ b/tests/rustdoc-ui/extract-doctests.stdout
@@ -0,0 +1 @@
+{"format_version":1,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":"#![allow(unused)]\nfn main() {\nlet\n}","name":"$DIR/extract-doctests.rs - (line 13)"}]}
\ No newline at end of file
diff --git a/tests/rustdoc/intra-doc/auxiliary/issue-103463-aux.rs b/tests/rustdoc-ui/intra-doc/auxiliary/issue-103463-aux.rs
index 2b8fdec1f12..2b8fdec1f12 100644
--- a/tests/rustdoc/intra-doc/auxiliary/issue-103463-aux.rs
+++ b/tests/rustdoc-ui/intra-doc/auxiliary/issue-103463-aux.rs
diff --git a/tests/rustdoc/intra-doc/issue-104145.rs b/tests/rustdoc-ui/intra-doc/ice-extern-trait-local-impl-104145.rs
index 5690803af5a..0e403b21c8a 100644
--- a/tests/rustdoc/intra-doc/issue-104145.rs
+++ b/tests/rustdoc-ui/intra-doc/ice-extern-trait-local-impl-104145.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/104145
+//@ check-pass
+
 // Doc links in `Trait`'s methods are resolved because it has a local impl.
 
 //@ aux-build:issue-103463-aux.rs
diff --git a/tests/rustdoc/intra-doc/issue-103463.rs b/tests/rustdoc-ui/intra-doc/ice-priv-use-103463.rs
index 9b5cb67fd32..10894282e55 100644
--- a/tests/rustdoc/intra-doc/issue-103463.rs
+++ b/tests/rustdoc-ui/intra-doc/ice-priv-use-103463.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/103463
+//@ check-pass
+
 // The `Trait` is not pulled into the crate resulting in doc links in its methods being resolved.
 
 //@ aux-build:issue-103463-aux.rs
diff --git a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr
index 180ba63927b..2c25589a553 100644
--- a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr
+++ b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr
@@ -99,7 +99,7 @@ LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
    |                    ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/invalid_const_in_lifetime_position.rs:2:10
    |
 LL | trait X {
diff --git a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr
index 72d1a52f710..1e52b699820 100644
--- a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr
+++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr
@@ -301,7 +301,7 @@ LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/ice-generic-type-alias-105742.rs:15:17
    |
 LL |    pub trait SVec: Index<
diff --git a/tests/rustdoc/inline_cross/issue-28480.rs b/tests/rustdoc/inline_cross/doc-hidden-broken-link-28480.rs
index 004510fd922..e1ca7403c03 100644
--- a/tests/rustdoc/inline_cross/issue-28480.rs
+++ b/tests/rustdoc/inline_cross/doc-hidden-broken-link-28480.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/28480
+#![crate_name="foobar"]
+
 //@ aux-build:rustdoc-hidden-sig.rs
 //@ build-aux-docs
 //@ ignore-cross-compile
@@ -7,7 +10,7 @@
 //@ has -  '//a' 'u8'
 extern crate rustdoc_hidden_sig;
 
-//@ has issue_28480/struct.Bar.html
+//@ has foobar/struct.Bar.html
 //@ !has -  '//a/@title' 'Hidden'
 //@ has -  '//a' 'u8'
 pub use rustdoc_hidden_sig::Bar;
diff --git a/tests/rustdoc/inline_cross/issue-31948-1.rs b/tests/rustdoc/inline_cross/doc-reachability-impl-31948-1.rs
index e59da87c29d..baab1da9547 100644
--- a/tests/rustdoc/inline_cross/issue-31948-1.rs
+++ b/tests/rustdoc/inline_cross/doc-reachability-impl-31948-1.rs
@@ -1,27 +1,30 @@
+// https://github.com/rust-lang/rust/issues/31948
+#![crate_name="foobar"]
+
 //@ aux-build:rustdoc-nonreachable-impls.rs
 //@ build-aux-docs
 //@ ignore-cross-compile
 
 extern crate rustdoc_nonreachable_impls;
 
-//@ has issue_31948_1/struct.Wobble.html
+//@ has foobar/struct.Wobble.html
 //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
 //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
 //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
-//@ has issue_31948_1/trait.Bark.html
+//@ has foobar/trait.Bark.html
 //@ has - '//h3[@class="code-header"]' 'for Foo'
 //@ has - '//h3[@class="code-header"]' 'for Wobble'
 //@ !has - '//h3[@class="code-header"]' 'for Wibble'
 pub use rustdoc_nonreachable_impls::Bark;
 
-//@ has issue_31948_1/trait.Woof.html
+//@ has foobar/trait.Woof.html
 //@ has - '//h3[@class="code-header"]' 'for Foo'
 //@ has - '//h3[@class="code-header"]' 'for Wobble'
 //@ !has - '//h3[@class="code-header"]' 'for Wibble'
 pub use rustdoc_nonreachable_impls::Woof;
 
-//@ !has issue_31948_1/trait.Bar.html
-//@ !has issue_31948_1/trait.Qux.html
+//@ !has foobar/trait.Bar.html
+//@ !has foobar/trait.Qux.html
diff --git a/tests/rustdoc/inline_cross/issue-31948-2.rs b/tests/rustdoc/inline_cross/doc-reachability-impl-31948-2.rs
index 34b57052883..40e9108ec62 100644
--- a/tests/rustdoc/inline_cross/issue-31948-2.rs
+++ b/tests/rustdoc/inline_cross/doc-reachability-impl-31948-2.rs
@@ -1,21 +1,24 @@
+// https://github.com/rust-lang/rust/issues/31948
+#![crate_name="foobar"]
+
 //@ aux-build:rustdoc-nonreachable-impls.rs
 //@ build-aux-docs
 //@ ignore-cross-compile
 
 extern crate rustdoc_nonreachable_impls;
 
-//@ has issue_31948_2/struct.Wobble.html
+//@ has foobar/struct.Wobble.html
 //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
 //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
 //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
 //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
-//@ has issue_31948_2/trait.Qux.html
+//@ has foobar/trait.Qux.html
 //@ has - '//h3[@class="code-header"]' 'for Foo'
 //@ has - '//h3[@class="code-header"]' 'for Wobble'
 pub use rustdoc_nonreachable_impls::hidden::Qux;
 
-//@ !has issue_31948_2/trait.Bar.html
-//@ !has issue_31948_2/trait.Woof.html
-//@ !has issue_31948_2/trait.Bark.html
+//@ !has foobar/trait.Bar.html
+//@ !has foobar/trait.Woof.html
+//@ !has foobar/trait.Bark.html
diff --git a/tests/rustdoc/inline_cross/issue-31948.rs b/tests/rustdoc/inline_cross/doc-reachability-impl-31948.rs
index 7a43fc7b279..ab0048513c7 100644
--- a/tests/rustdoc/inline_cross/issue-31948.rs
+++ b/tests/rustdoc/inline_cross/doc-reachability-impl-31948.rs
@@ -1,29 +1,32 @@
+// https://github.com/rust-lang/rust/issues/31948
+#![crate_name="foobar"]
+
 //@ aux-build:rustdoc-nonreachable-impls.rs
 //@ build-aux-docs
 //@ ignore-cross-compile
 
 extern crate rustdoc_nonreachable_impls;
 
-//@ has issue_31948/struct.Foo.html
+//@ has foobar/struct.Foo.html
 //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for'
 //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for'
 //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for'
 //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for'
 pub use rustdoc_nonreachable_impls::Foo;
 
-//@ has issue_31948/trait.Bark.html
+//@ has foobar/trait.Bark.html
 //@ has - '//h3[@class="code-header"]' 'for Foo'
 //@ !has - '//h3[@class="code-header"]' 'for Wibble'
 //@ !has - '//h3[@class="code-header"]' 'for Wobble'
 pub use rustdoc_nonreachable_impls::Bark;
 
-//@ has issue_31948/trait.Woof.html
+//@ has foobar/trait.Woof.html
 //@ has - '//h3[@class="code-header"]' 'for Foo'
 //@ !has - '//h3[@class="code-header"]' 'for Wibble'
 //@ !has - '//h3[@class="code-header"]' 'for Wobble'
 pub use rustdoc_nonreachable_impls::Woof;
 
-//@ !has issue_31948/trait.Bar.html
-//@ !has issue_31948/trait.Qux.html
-//@ !has issue_31948/struct.Wibble.html
-//@ !has issue_31948/struct.Wobble.html
+//@ !has foobar/trait.Bar.html
+//@ !has foobar/trait.Qux.html
+//@ !has foobar/struct.Wibble.html
+//@ !has foobar/struct.Wobble.html
diff --git a/tests/rustdoc/inline_cross/issue-32881.rs b/tests/rustdoc/inline_cross/impl-dyn-trait-32881.rs
index d4ebf10a1ca..f7dc7414455 100644
--- a/tests/rustdoc/inline_cross/issue-32881.rs
+++ b/tests/rustdoc/inline_cross/impl-dyn-trait-32881.rs
@@ -1,10 +1,13 @@
+// https://github.com/rust-lang/rust/issues/32881
+#![crate_name="foobar"]
+
 //@ aux-build:rustdoc-trait-object-impl.rs
 //@ build-aux-docs
 //@ ignore-cross-compile
 
 extern crate rustdoc_trait_object_impl;
 
-//@ has issue_32881/trait.Bar.html
+//@ has foobar/trait.Bar.html
 //@ has - '//h3[@class="code-header"]' "impl<'a> dyn Bar"
 //@ has - '//h3[@class="code-header"]' "impl<'a> Debug for dyn Bar"
 
diff --git a/tests/rustdoc/inline_cross/issue-33113.rs b/tests/rustdoc/inline_cross/impl-ref-33113.rs
index 05e87d962cb..9ac4f02e00c 100644
--- a/tests/rustdoc/inline_cross/issue-33113.rs
+++ b/tests/rustdoc/inline_cross/impl-ref-33113.rs
@@ -1,10 +1,13 @@
+// https://github.com/rust-lang/rust/issues/33113
+#![crate_name="foobar"]
+
 //@ aux-build:issue-33113.rs
 //@ build-aux-docs
 //@ ignore-cross-compile
 
 extern crate bar;
 
-//@ has issue_33113/trait.Bar.html
+//@ has foobar/trait.Bar.html
 //@ has - '//h3[@class="code-header"]' "for &'a char"
 //@ has - '//h3[@class="code-header"]' "for Foo"
 pub use bar::Bar;
diff --git a/tests/rustdoc/inline_cross/issue-76736-1.rs b/tests/rustdoc/inline_cross/rustc-private-76736-1.rs
index fe52702fd6f..3ffa5e6cc06 100644
--- a/tests/rustdoc/inline_cross/issue-76736-1.rs
+++ b/tests/rustdoc/inline_cross/rustc-private-76736-1.rs
@@ -1,3 +1,5 @@
+// https://github.com/rust-lang/rust/issues/76736
+
 //@ aux-build:issue-76736-1.rs
 //@ aux-build:issue-76736-2.rs
 
diff --git a/tests/rustdoc/inline_cross/issue-76736-2.rs b/tests/rustdoc/inline_cross/rustc-private-76736-2.rs
index df376ebe9a1..843b2941602 100644
--- a/tests/rustdoc/inline_cross/issue-76736-2.rs
+++ b/tests/rustdoc/inline_cross/rustc-private-76736-2.rs
@@ -1,3 +1,5 @@
+// https://github.com/rust-lang/rust/issues/76736
+
 //@ aux-build:issue-76736-1.rs
 //@ aux-build:issue-76736-2.rs
 
diff --git a/tests/rustdoc/inline_cross/issue-76736-3.rs b/tests/rustdoc/inline_cross/rustc-private-76736-3.rs
index 1bed4621c04..f9b46caa02f 100644
--- a/tests/rustdoc/inline_cross/issue-76736-3.rs
+++ b/tests/rustdoc/inline_cross/rustc-private-76736-3.rs
@@ -1,3 +1,5 @@
+// https://github.com/rust-lang/rust/issues/76736
+
 //@ compile-flags: -Zforce-unstable-if-unmarked
 //@ aux-build:issue-76736-1.rs
 //@ aux-build:issue-76736-2.rs
diff --git a/tests/rustdoc/inline_cross/issue-76736-4.rs b/tests/rustdoc/inline_cross/rustc-private-76736-4.rs
index 487e9030108..511464f2c49 100644
--- a/tests/rustdoc/inline_cross/issue-76736-4.rs
+++ b/tests/rustdoc/inline_cross/rustc-private-76736-4.rs
@@ -1,3 +1,5 @@
+// https://github.com/rust-lang/rust/issues/76736
+
 //@ aux-build:issue-76736-1.rs
 //@ aux-build:issue-76736-2.rs
 
diff --git a/tests/rustdoc/inline_cross/issue-24183.method_no_where_self_sized.html b/tests/rustdoc/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html
index f3c1c045202..f3c1c045202 100644
--- a/tests/rustdoc/inline_cross/issue-24183.method_no_where_self_sized.html
+++ b/tests/rustdoc/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html
diff --git a/tests/rustdoc/inline_cross/issue-24183.rs b/tests/rustdoc/inline_cross/self-sized-bounds-24183.rs
index 8299eecc575..909005532f5 100644
--- a/tests/rustdoc/inline_cross/issue-24183.rs
+++ b/tests/rustdoc/inline_cross/self-sized-bounds-24183.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/24183
 #![crate_type = "lib"]
 #![crate_name = "usr"]
 
diff --git a/tests/rustdoc/inline_local/issue-32343.rs b/tests/rustdoc/inline_local/doc-no-inline-32343.rs
index 2ec123fdc5c..ed11614a500 100644
--- a/tests/rustdoc/inline_local/issue-32343.rs
+++ b/tests/rustdoc/inline_local/doc-no-inline-32343.rs
@@ -1,12 +1,15 @@
-//@ !has issue_32343/struct.Foo.html
-//@ has issue_32343/index.html
+// https://github.com/rust-lang/rust/issues/32343
+#![crate_name="foobar"]
+
+//@ !has foobar/struct.Foo.html
+//@ has foobar/index.html
 //@ has - '//code' 'pub use foo::Foo'
 //@ !has - '//code/a' 'Foo'
 #[doc(no_inline)]
 pub use foo::Foo;
 
-//@ !has issue_32343/struct.Bar.html
-//@ has issue_32343/index.html
+//@ !has foobar/struct.Bar.html
+//@ has foobar/index.html
 //@ has - '//code' 'pub use foo::Bar'
 //@ has - '//code/a' 'Bar'
 #[doc(no_inline)]
@@ -18,6 +21,6 @@ mod foo {
 }
 
 pub mod bar {
-    //@ has issue_32343/bar/struct.Bar.html
+    //@ has foobar/bar/struct.Bar.html
     pub use ::foo::Bar;
 }
diff --git a/tests/rustdoc/inline_local/fully-stable-path-is-better.rs b/tests/rustdoc/inline_local/fully-stable-path-is-better.rs
index 88b0b0d57b0..41bf42d2e7a 100644
--- a/tests/rustdoc/inline_local/fully-stable-path-is-better.rs
+++ b/tests/rustdoc/inline_local/fully-stable-path-is-better.rs
@@ -16,10 +16,10 @@ pub mod stb1 {
 #[unstable(feature = "uns", issue = "135003")]
 pub mod uns {
     #[stable(since = "1.0", feature = "stb1")]
-    #[rustc_allowed_through_unstable_modules]
+    #[rustc_allowed_through_unstable_modules = "use stable path instead"]
     pub struct Inside1;
     #[stable(since = "1.0", feature = "stb2")]
-    #[rustc_allowed_through_unstable_modules]
+    #[rustc_allowed_through_unstable_modules = "use stable path instead"]
     pub struct Inside2;
 }
 
diff --git a/tests/rustdoc/inline_local/issue-28537.rs b/tests/rustdoc/inline_local/pub-re-export-28537.rs
index d5ba94d2e6c..0e9836c7cee 100644
--- a/tests/rustdoc/inline_local/issue-28537.rs
+++ b/tests/rustdoc/inline_local/pub-re-export-28537.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/28537
+#![crate_name="foo"]
+
 #[doc(hidden)]
 pub mod foo {
     pub struct Foo;
@@ -10,8 +13,8 @@ mod bar {
     }
 }
 
-//@ has issue_28537/struct.Foo.html
+//@ has foo/struct.Foo.html
 pub use foo::Foo;
 
-//@ has issue_28537/struct.Bar.html
+//@ has foo/struct.Bar.html
 pub use self::bar::Bar;
diff --git a/tests/rustdoc/intra-doc/issue-82209.rs b/tests/rustdoc/intra-doc/enum-self-82209.rs
index 46d028e535c..615115a5f8b 100644
--- a/tests/rustdoc/intra-doc/issue-82209.rs
+++ b/tests/rustdoc/intra-doc/enum-self-82209.rs
@@ -1,3 +1,5 @@
+// https://github.com/rust-lang/rust/issues/82209
+
 #![crate_name = "foo"]
 #![deny(rustdoc::broken_intra_doc_links)]
 pub enum Foo {
diff --git a/tests/rustdoc/intra-doc/issue-108459.rs b/tests/rustdoc/intra-doc/link-same-name-different-disambiguator-108459.rs
index 18424c069d3..0b339eaf6b2 100644
--- a/tests/rustdoc/intra-doc/issue-108459.rs
+++ b/tests/rustdoc/intra-doc/link-same-name-different-disambiguator-108459.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/pull/108459
+#![crate_name="foobar"]
+
 #![deny(rustdoc::broken_intra_doc_links)]
 #![allow(rustdoc::redundant_explicit_links)]
 
@@ -13,13 +16,13 @@ pub struct MyStruct1;
 // the same target but different text
 
 /// See also [crate::char] and [mod@char] and [prim@char]
-//@ has issue_108459/struct.MyStruct2.html '//*[@href="char/index.html"]' 'crate::char'
+//@ has foobar/struct.MyStruct2.html '//*[@href="char/index.html"]' 'crate::char'
 //@ has - '//*[@href="char/index.html"]' 'char'
 //@ has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char'
 pub struct MyStruct2;
 
 /// See also [mod@char] and [prim@char] and [crate::char]
-//@ has issue_108459/struct.MyStruct3.html '//*[@href="char/index.html"]' 'crate::char'
+//@ has foobar/struct.MyStruct3.html '//*[@href="char/index.html"]' 'crate::char'
 //@ has - '//*[@href="char/index.html"]' 'char'
 //@ has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char'
 pub struct MyStruct3;
@@ -28,11 +31,11 @@ pub struct MyStruct3;
 // different targets
 
 /// See also [char][mod@char] and [char][prim@char]
-//@ has issue_108459/struct.MyStruct4.html '//*[@href="char/index.html"]' 'char'
+//@ has foobar/struct.MyStruct4.html '//*[@href="char/index.html"]' 'char'
 //@ has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char'
 pub struct MyStruct4;
 
 /// See also [char][prim@char] and [char][crate::char]
-//@ has issue_108459/struct.MyStruct5.html '//*[@href="char/index.html"]' 'char'
+//@ has foobar/struct.MyStruct5.html '//*[@href="char/index.html"]' 'char'
 //@ has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char'
 pub struct MyStruct5;
diff --git a/tests/rustdoc/intra-doc/issue-66159.rs b/tests/rustdoc/intra-doc/same-name-different-crates-66159.rs
index 5d50f63f299..7e3ace9355a 100644
--- a/tests/rustdoc/intra-doc/issue-66159.rs
+++ b/tests/rustdoc/intra-doc/same-name-different-crates-66159.rs
@@ -1,3 +1,6 @@
+// https://github.com/rust-lang/rust/issues/66159
+#![crate_name="foobar"]
+
 //@ aux-crate:priv:pub_struct=pub-struct.rs
 //@ compile-flags:-Z unstable-options
 
@@ -6,5 +9,5 @@
 // Since we don't generate the docs for the auxiliary files, we can't actually
 // verify that the struct is linked correctly.
 
-//@ has issue_66159/index.html
+//@ has foobar/index.html
 //! [pub_struct::SomeStruct]
diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs
index b74abb0e0ba..22cd4b9cd59 100644
--- a/tests/rustdoc/stability.rs
+++ b/tests/rustdoc/stability.rs
@@ -85,7 +85,7 @@ pub mod stable_later {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_allowed_through_unstable_modules]
+#[rustc_allowed_through_unstable_modules = "use stable path instead"]
 pub mod stable_earlier1 {
     //@ has stability/stable_earlier1/struct.StableInUnstable.html \
     //      '//div[@class="main-heading"]//span[@class="since"]' '1.0.0'
diff --git a/tests/ui-fulldeps/obtain-borrowck.rs b/tests/ui-fulldeps/obtain-borrowck.rs
index f8064c245a8..c6bec4f77a0 100644
--- a/tests/ui-fulldeps/obtain-borrowck.rs
+++ b/tests/ui-fulldeps/obtain-borrowck.rs
@@ -48,7 +48,6 @@ fn main() {
         let mut callbacks = CompilerCalls::default();
         // Call the Rust compiler with our callbacks.
         rustc_driver::run_compiler(&rustc_args, &mut callbacks);
-        Ok(())
     });
     std::process::exit(exit_code);
 }
diff --git a/tests/ui/abi/segfault-no-out-of-stack.rs b/tests/ui/abi/segfault-no-out-of-stack.rs
index b5af13ebfb5..5e8b4e0dbf2 100644
--- a/tests/ui/abi/segfault-no-out-of-stack.rs
+++ b/tests/ui/abi/segfault-no-out-of-stack.rs
@@ -1,5 +1,6 @@
 //@ run-pass
 //@ needs-subprocess
+//@ compile-flags: -Zub-checks=no -Zmir-enable-passes=-CheckNull
 //@ ignore-fuchsia must translate zircon signal to SIGSEGV/SIGBUS, FIXME (#58590)
 
 #![feature(rustc_private)]
diff --git a/tests/ui/array-slice-vec/driftsort-off-by-one-issue-136103.rs b/tests/ui/array-slice-vec/driftsort-off-by-one-issue-136103.rs
new file mode 100644
index 00000000000..42197ff102d
--- /dev/null
+++ b/tests/ui/array-slice-vec/driftsort-off-by-one-issue-136103.rs
@@ -0,0 +1,10 @@
+//@ run-pass
+// Ensures that driftsort doesn't crash under specific slice
+// length and memory size.
+// Based on the example given in https://github.com/rust-lang/rust/issues/136103.
+fn main() {
+    let n = 127;
+    let mut objs: Vec<_> =
+        (0..n).map(|i| [(i % 2) as u8; 125001]).collect();
+    objs.sort();
+}
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32e.stderr b/tests/ui/asm/riscv/bad-reg.riscv32e.stderr
index 409178df9c5..27c8e958e53 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32e.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32e.stderr
@@ -22,170 +22,164 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: cannot use register `x16`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:48:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", out("x16") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x17`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:50:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("x17") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x18`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:50:18
    |
 LL |         asm!("", out("x18") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x19`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:54:18
+  --> $DIR/bad-reg.rs:52:18
    |
 LL |         asm!("", out("x19") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x20`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:56:18
+  --> $DIR/bad-reg.rs:54:18
    |
 LL |         asm!("", out("x20") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x21`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:58:18
+  --> $DIR/bad-reg.rs:56:18
    |
 LL |         asm!("", out("x21") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x22`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:60:18
+  --> $DIR/bad-reg.rs:58:18
    |
 LL |         asm!("", out("x22") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x23`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:62:18
+  --> $DIR/bad-reg.rs:60:18
    |
 LL |         asm!("", out("x23") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x24`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:64:18
+  --> $DIR/bad-reg.rs:62:18
    |
 LL |         asm!("", out("x24") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x25`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:66:18
+  --> $DIR/bad-reg.rs:64:18
    |
 LL |         asm!("", out("x25") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x26`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:68:18
+  --> $DIR/bad-reg.rs:66:18
    |
 LL |         asm!("", out("x26") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x27`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:70:18
+  --> $DIR/bad-reg.rs:68:18
    |
 LL |         asm!("", out("x27") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x28`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:72:18
+  --> $DIR/bad-reg.rs:70:18
    |
 LL |         asm!("", out("x28") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x29`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:74:18
+  --> $DIR/bad-reg.rs:72:18
    |
 LL |         asm!("", out("x29") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x30`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:76:18
+  --> $DIR/bad-reg.rs:74:18
    |
 LL |         asm!("", out("x30") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x31`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:78:18
+  --> $DIR/bad-reg.rs:76:18
    |
 LL |         asm!("", out("x31") _);
    |                  ^^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:82:26
+  --> $DIR/bad-reg.rs:80:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:84:26
+  --> $DIR/bad-reg.rs:82:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:86:26
+  --> $DIR/bad-reg.rs:84:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:89:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -193,7 +187,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -201,12 +195,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 34 previous errors
+error: aborting due to 33 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr b/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr
index 4770e70cc2b..4ff03d819e6 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr
@@ -22,50 +22,44 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -73,7 +67,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -81,12 +75,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32i.stderr b/tests/ui/asm/riscv/bad-reg.riscv32i.stderr
index ae7db1554b1..fbe63eb0563 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32i.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32i.stderr
@@ -22,74 +22,68 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:82:26
+  --> $DIR/bad-reg.rs:80:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:84:26
+  --> $DIR/bad-reg.rs:82:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:86:26
+  --> $DIR/bad-reg.rs:84:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:89:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -97,7 +91,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -105,12 +99,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 18 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr b/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr
index 8bc5c9a87fc..57664cfe893 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr
@@ -22,50 +22,44 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: `d` target feature is not enabled
-  --> $DIR/bad-reg.rs:86:35
+  --> $DIR/bad-reg.rs:84:35
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                                   ^
@@ -73,7 +67,7 @@ LL |         asm!("/* {} */", in(freg) d);
    = note: this is required to use type `f64` with register class `freg`
 
 error: `d` target feature is not enabled
-  --> $DIR/bad-reg.rs:89:36
+  --> $DIR/bad-reg.rs:87:36
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                                    ^
@@ -81,7 +75,7 @@ LL |         asm!("/* {} */", out(freg) d);
    = note: this is required to use type `f64` with register class `freg`
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -89,7 +83,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -97,12 +91,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 16 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr b/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr
index 4770e70cc2b..4ff03d819e6 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr
@@ -22,50 +22,44 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -73,7 +67,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -81,12 +75,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr b/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr
index ae7db1554b1..fbe63eb0563 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr
@@ -22,74 +22,68 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:82:26
+  --> $DIR/bad-reg.rs:80:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:84:26
+  --> $DIR/bad-reg.rs:82:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:86:26
+  --> $DIR/bad-reg.rs:84:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:89:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -97,7 +91,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -105,12 +99,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 18 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.rs b/tests/ui/asm/riscv/bad-reg.rs
index 7f0fc00d548..7d032d277aa 100644
--- a/tests/ui/asm/riscv/bad-reg.rs
+++ b/tests/ui/asm/riscv/bad-reg.rs
@@ -38,8 +38,6 @@ fn f() {
         //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
         asm!("", out("gp") _);
         //~^ ERROR invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-        asm!("", out("gp") _);
-        //~^ ERROR invalid register `gp`: the global pointer cannot be used as an operand for inline asm
         asm!("", out("tp") _);
         //~^ ERROR invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
         asm!("", out("zero") _);
diff --git a/tests/ui/associated-consts/associated-const-in-trait.stderr b/tests/ui/associated-consts/associated-const-in-trait.stderr
index 107ceeaf113..5aaa6f6be05 100644
--- a/tests/ui/associated-consts/associated-const-in-trait.stderr
+++ b/tests/ui/associated-consts/associated-const-in-trait.stderr
@@ -5,7 +5,7 @@ LL | impl dyn Trait {
    |      ^^^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/associated-const-in-trait.rs:4:11
    |
 LL | trait Trait {
@@ -21,7 +21,7 @@ LL |     const fn n() -> usize { Self::N }
    |                             ^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/associated-const-in-trait.rs:4:11
    |
 LL | trait Trait {
diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
index bf53089675d..81ace4ebb6d 100644
--- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
+++ b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
@@ -5,6 +5,8 @@ LL | fn main() -> Foo::Bar::<Vec<[u32]>> {}
    |                         ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[u32]`
+note: required by an implicit `Sized` bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-item/issue-48027.stderr b/tests/ui/associated-item/issue-48027.stderr
index 1baaefd7720..513961e2bd0 100644
--- a/tests/ui/associated-item/issue-48027.stderr
+++ b/tests/ui/associated-item/issue-48027.stderr
@@ -5,7 +5,7 @@ LL | impl dyn Bar {}
    |      ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-48027.rs:2:11
    |
 LL | trait Bar {
diff --git a/tests/ui/async-await/async-closures/is-not-fn.current.stderr b/tests/ui/async-await/async-closures/is-not-fn.current.stderr
index e7be1d5b10e..0fab1c15f27 100644
--- a/tests/ui/async-await/async-closures/is-not-fn.current.stderr
+++ b/tests/ui/async-await/async-closures/is-not-fn.current.stderr
@@ -1,4 +1,4 @@
-error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
+error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to return `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
   --> $DIR/is-not-fn.rs:8:14
    |
 LL |     needs_fn(async || {});
diff --git a/tests/ui/async-await/async-closures/is-not-fn.next.stderr b/tests/ui/async-await/async-closures/is-not-fn.next.stderr
index e7be1d5b10e..0fab1c15f27 100644
--- a/tests/ui/async-await/async-closures/is-not-fn.next.stderr
+++ b/tests/ui/async-await/async-closures/is-not-fn.next.stderr
@@ -1,4 +1,4 @@
-error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
+error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to return `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
   --> $DIR/is-not-fn.rs:8:14
    |
 LL |     needs_fn(async || {});
diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs
index eacd07b7cdd..e5ab4742dab 100644
--- a/tests/ui/async-await/async-closures/is-not-fn.rs
+++ b/tests/ui/async-await/async-closures/is-not-fn.rs
@@ -6,5 +6,5 @@
 fn main() {
     fn needs_fn(x: impl FnOnce()) {}
     needs_fn(async || {});
-    //~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`
+    //~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to return `()`
 }
diff --git a/tests/ui/async-await/async-fn/dyn-pos.stderr b/tests/ui/async-await/async-fn/dyn-pos.stderr
index f9d2a669477..7d5b37bdbe7 100644
--- a/tests/ui/async-await/async-fn/dyn-pos.stderr
+++ b/tests/ui/async-await/async-fn/dyn-pos.stderr
@@ -5,7 +5,7 @@ LL | fn foo(x: &dyn AsyncFn()) {}
    |                ^^^^^^^^^ `AsyncFnMut` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
    |
    = note: the trait is not dyn compatible because it contains the generic associated type `CallRefFuture`
diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
index b60f6a08338..ce023397db9 100644
--- a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
+++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
@@ -20,19 +20,15 @@ LL |         true
    = note: expected enum `Option<()>`
               found type `bool`
 
-error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10}` to be a closure that returns `bool`, but it returns `Option<()>`
-  --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10
+error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10}` to return `bool`, but it returns `Option<()>`
+  --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:16
    |
-LL |       call(|| -> Option<()> {
-   |  _____----_^
-   | |     |
-   | |     required by a bound introduced by this call
-LL | |
-LL | |         if true {
-LL | |             false
-...  |
-LL | |     })
-   | |_____^ expected `bool`, found `Option<()>`
+LL |     call(|| -> Option<()> {
+   |     ---- ------^^^^^^^^^^
+   |     |    |     |
+   |     |    |     expected `bool`, found `Option<()>`
+   |     |    this closure
+   |     required by a bound introduced by this call
    |
    = note: expected type `bool`
               found enum `Option<()>`
diff --git a/tests/ui/async-await/in-trait/dyn-compatibility.stderr b/tests/ui/async-await/in-trait/dyn-compatibility.stderr
index c6c406902f6..553bcbf89d5 100644
--- a/tests/ui/async-await/in-trait/dyn-compatibility.stderr
+++ b/tests/ui/async-await/in-trait/dyn-compatibility.stderr
@@ -5,7 +5,7 @@ LL |     let x: &dyn Foo = todo!();
    |            ^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-compatibility.rs:5:14
    |
 LL | trait Foo {
diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr
index a674fc0f3a5..1fccc32470f 100644
--- a/tests/ui/async-await/inference_var_self_argument.stderr
+++ b/tests/ui/async-await/inference_var_self_argument.stderr
@@ -14,7 +14,7 @@ LL |     async fn foo(self: &dyn Foo) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/inference_var_self_argument.rs:5:14
    |
 LL | trait Foo {
diff --git a/tests/ui/async-await/issue-98634.rs b/tests/ui/async-await/issue-98634.rs
index 02e869f4325..3bfc2bf8a7c 100644
--- a/tests/ui/async-await/issue-98634.rs
+++ b/tests/ui/async-await/issue-98634.rs
@@ -43,8 +43,8 @@ impl Runtime {
 fn main() {
     Runtime.block_on(async {
         StructAsync { callback }.await;
-        //~^ ERROR expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
-        //~| ERROR expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
-        //~| ERROR expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
+        //~^ ERROR expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
+        //~| ERROR expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
+        //~| ERROR expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
     });
 }
diff --git a/tests/ui/async-await/issue-98634.stderr b/tests/ui/async-await/issue-98634.stderr
index 574904ceafa..e0739ae3a9b 100644
--- a/tests/ui/async-await/issue-98634.stderr
+++ b/tests/ui/async-await/issue-98634.stderr
@@ -1,4 +1,4 @@
-error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
+error[E0271]: expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
   --> $DIR/issue-98634.rs:45:23
    |
 LL |         StructAsync { callback }.await;
@@ -10,7 +10,7 @@ note: required by a bound in `StructAsync`
 LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
 
-error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
+error[E0271]: expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
   --> $DIR/issue-98634.rs:45:9
    |
 LL |         StructAsync { callback }.await;
@@ -22,7 +22,7 @@ note: required by a bound in `StructAsync`
 LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
 
-error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
+error[E0271]: expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
   --> $DIR/issue-98634.rs:45:34
    |
 LL |         StructAsync { callback }.await;
diff --git a/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.rs b/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.rs
new file mode 100644
index 00000000000..934aac8383d
--- /dev/null
+++ b/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.rs
@@ -0,0 +1,46 @@
+// https://github.com/rust-lang/rust/issues/133941
+use std::marker::PhantomData;
+
+struct Bar<'a>(PhantomData<&'a mut i32>);
+
+impl<'a> Drop for Bar<'a> {
+    fn drop(&mut self) {}
+}
+
+struct Foo();
+
+impl Foo {
+    fn f(&mut self) -> Option<Bar<'_>> {
+        None
+    }
+
+    fn g(&mut self) {}
+}
+
+fn main() {
+    let mut foo = Foo();
+    while let Some(_) = foo.f() {
+        //~^ HELP matches!
+        foo.g();
+        //~^ ERROR [E0499]
+    }
+    if let Some(_) = foo.f() {
+        //~^ HELP matches!
+        foo.g();
+        //~^ ERROR [E0499]
+    }
+    while let Some(_x) = foo.f() {
+        foo.g();
+        //~^ ERROR [E0499]
+    }
+    if let Some(_x) = foo.f() {
+        foo.g();
+        //~^ ERROR [E0499]
+    }
+    while let Some(_x) = {let _x = foo.f(); foo.g(); None::<()>} {
+        //~^ ERROR [E0499]
+    }
+    if let Some(_x) = {let _x = foo.f(); foo.g(); None::<()>} {
+        //~^ ERROR [E0499]
+    }
+}
diff --git a/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.stderr b/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.stderr
new file mode 100644
index 00000000000..bb21caccbaf
--- /dev/null
+++ b/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.stderr
@@ -0,0 +1,89 @@
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:24:9
+   |
+LL |     while let Some(_) = foo.f() {
+   |                         -------
+   |                         |
+   |                         first mutable borrow occurs here
+   |                         a temporary with access to the first borrow is created here ...
+LL |
+LL |         foo.g();
+   |         ^^^ second mutable borrow occurs here
+LL |
+LL |     }
+   |     - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<Bar<'_>>`
+   |
+help: consider using the `matches!` macro
+   |
+LL |     while matches!(foo.f(), Some(_)) {
+   |           ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:29:9
+   |
+LL |     if let Some(_) = foo.f() {
+   |                      -------
+   |                      |
+   |                      first mutable borrow occurs here
+   |                      a temporary with access to the first borrow is created here ...
+LL |
+LL |         foo.g();
+   |         ^^^ second mutable borrow occurs here
+LL |
+LL |     }
+   |     - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<Bar<'_>>`
+   |
+help: consider using the `matches!` macro
+   |
+LL |     if matches!(foo.f(), Some(_)) {
+   |        ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:33:9
+   |
+LL |     while let Some(_x) = foo.f() {
+   |                          -------
+   |                          |
+   |                          first mutable borrow occurs here
+   |                          a temporary with access to the first borrow is created here ...
+LL |         foo.g();
+   |         ^^^ second mutable borrow occurs here
+LL |
+LL |     }
+   |     - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<Bar<'_>>`
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:37:9
+   |
+LL |     if let Some(_x) = foo.f() {
+   |                       -------
+   |                       |
+   |                       first mutable borrow occurs here
+   |                       a temporary with access to the first borrow is created here ...
+LL |         foo.g();
+   |         ^^^ second mutable borrow occurs here
+LL |
+LL |     }
+   |     - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<Bar<'_>>`
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:40:45
+   |
+LL |     while let Some(_x) = {let _x = foo.f(); foo.g(); None::<()>} {
+   |                                    ---      ^^^                - first borrow might be used here, when `_x` is dropped and runs the destructor for type `Option<Bar<'_>>`
+   |                                    |        |
+   |                                    |        second mutable borrow occurs here
+   |                                    first mutable borrow occurs here
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:43:42
+   |
+LL |     if let Some(_x) = {let _x = foo.f(); foo.g(); None::<()>} {
+   |                                 ---      ^^^                - first borrow might be used here, when `_x` is dropped and runs the destructor for type `Option<Bar<'_>>`
+   |                                 |        |
+   |                                 |        second mutable borrow occurs here
+   |                                 first mutable borrow occurs here
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/borrowck/issue-93093.rs b/tests/ui/borrowck/issue-93093.rs
index e85b296c983..1521b207238 100644
--- a/tests/ui/borrowck/issue-93093.rs
+++ b/tests/ui/borrowck/issue-93093.rs
@@ -4,7 +4,7 @@ struct S {
 }
 impl S {
     async fn bar(&self) { //~ HELP consider changing this to be a mutable reference
-        //~| SUGGESTION &mut self
+        //~| SUGGESTION mut
         self.foo += 1; //~ ERROR cannot assign to `self.foo`, which is behind a `&` reference [E0594]
     }
 }
diff --git a/tests/ui/borrowck/issue-93093.stderr b/tests/ui/borrowck/issue-93093.stderr
index b6a2768b61d..d788ce33197 100644
--- a/tests/ui/borrowck/issue-93093.stderr
+++ b/tests/ui/borrowck/issue-93093.stderr
@@ -7,7 +7,7 @@ LL |         self.foo += 1;
 help: consider changing this to be a mutable reference
    |
 LL |     async fn bar(&mut self) {
-   |                  ~~~~~~~~~
+   |                   +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
index 5c70eccfbd3..190ddeaa8f2 100644
--- a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
+++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
@@ -41,7 +41,7 @@ LL |         let a16 = self.read_word() as u16;
 help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
    |
 LL |     extern "C" fn read_dword(&'_ mut self) -> u16 {
-   |                              ~~~~~~~~~~~~
+   |                                  +++
 
 error[E0596]: cannot borrow `*self` as mutable, as it is behind a `&` reference
   --> $DIR/trait-impl-argument-difference-ice.rs:18:19
@@ -52,7 +52,7 @@ LL |         let b16 = self.read_word() as u16;
 help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
    |
 LL |     extern "C" fn read_dword(&'_ mut self) -> u16 {
-   |                              ~~~~~~~~~~~~
+   |                                  +++
 
 error: aborting due to 5 previous errors; 1 warning emitted
 
diff --git a/tests/ui/closures/return-type-doesnt-match-bound.rs b/tests/ui/closures/return-type-doesnt-match-bound.rs
new file mode 100644
index 00000000000..af15385d4b0
--- /dev/null
+++ b/tests/ui/closures/return-type-doesnt-match-bound.rs
@@ -0,0 +1,25 @@
+use std::error::Error;
+use std::process::exit;
+
+fn foo<F>(f: F) -> ()
+where
+    F: FnOnce() -> Result<(), Box<dyn Error>>,
+{
+    f().or_else(|e| -> ! { //~ ERROR to return
+        eprintln!("{:?}", e);
+        exit(1)
+    });
+}
+
+fn bar<F>(f: F) -> ()
+where
+    F: FnOnce() -> Result<(), Box<dyn Error>>,
+{
+    let c = |e| -> ! { //~ ERROR to return
+        eprintln!("{:?}", e);
+        exit(1)
+    };
+    f().or_else(c);
+}
+
+fn main() {}
diff --git a/tests/ui/closures/return-type-doesnt-match-bound.stderr b/tests/ui/closures/return-type-doesnt-match-bound.stderr
new file mode 100644
index 00000000000..c0bc2f6084c
--- /dev/null
+++ b/tests/ui/closures/return-type-doesnt-match-bound.stderr
@@ -0,0 +1,37 @@
+error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:8:17}` to return `Result<(), _>`, but it returns `!`
+  --> $DIR/return-type-doesnt-match-bound.rs:8:24
+   |
+LL |     f().or_else(|e| -> ! {
+   |         ------- -------^
+   |         |       |      |
+   |         |       |      expected `Result<(), _>`, found `!`
+   |         |       this closure
+   |         required by a bound introduced by this call
+   |
+   = note: expected enum `Result<(), _>`
+              found type `!`
+note: required by a bound in `Result::<T, E>::or_else`
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+
+error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:18:13}` to return `Result<(), _>`, but it returns `!`
+  --> $DIR/return-type-doesnt-match-bound.rs:18:20
+   |
+LL |     let c = |e| -> ! {
+   |             -------^
+   |             |      |
+   |             |      expected `Result<(), _>`, found `!`
+   |             this closure
+...
+LL |     f().or_else(c);
+   |         ------- - closure used here
+   |         |
+   |         required by a bound introduced by this call
+   |
+   = note: expected enum `Result<(), _>`
+              found type `!`
+note: required by a bound in `Result::<T, E>::or_else`
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr
index 0c220a13876..b682bdac034 100644
--- a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr
+++ b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr
@@ -29,7 +29,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:14:27
    |
 LL |     let _ = type_ascribe!(Box::new( { |x| (x as u8) }), Box<dyn Fn(i32) -> _>);
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@coerce-expect-unsized-ascribed.rs:14:39}>`
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@...}>`
    |
    = note: expected struct `Box<dyn Fn(i32) -> u8>`
               found struct `Box<{closure@$DIR/coerce-expect-unsized-ascribed.rs:14:39: 14:42}>`
@@ -85,7 +85,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:22:27
    |
 LL |     let _ = type_ascribe!(&{ |x| (x as u8) }, &dyn Fn(i32) -> _);
-   |                           ^^^^^^^^^^^^^^^^^^ expected `&dyn Fn(i32) -> u8`, found `&{closure@coerce-expect-unsized-ascribed.rs:22:30}`
+   |                           ^^^^^^^^^^^^^^^^^^ expected `&dyn Fn(i32) -> u8`, found `&{closure@...}`
    |
    = note: expected reference `&dyn Fn(i32) -> u8`
               found reference `&{closure@$DIR/coerce-expect-unsized-ascribed.rs:22:30: 22:33}`
@@ -123,7 +123,7 @@ error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:27:27
    |
 LL |     let _ = type_ascribe!(Box::new(|x| (x as u8)), Box<dyn Fn(i32) -> _>);
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@coerce-expect-unsized-ascribed.rs:27:36}>`
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@...}>`
    |
    = note: expected struct `Box<dyn Fn(i32) -> u8>`
               found struct `Box<{closure@$DIR/coerce-expect-unsized-ascribed.rs:27:36: 27:39}>`
diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr
index 20257bbaf28..033bfee226f 100644
--- a/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr
+++ b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr
@@ -5,7 +5,7 @@ LL | impl DynIncompatible for dyn DynIncompatible { }
    |                          ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/coherence-impl-trait-for-trait-dyn-compatible.rs:6:45
    |
 LL | trait DynIncompatible { fn eq(&self, other: Self); }
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr
index cd7f3a3c21d..6fa9b591ad2 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr
@@ -5,7 +5,7 @@ LL | fn foo(a: &dyn ConstParamTy_) {}
    |                ^^^^^^^^^^^^^ `ConstParamTy_` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    |
    = note: the trait is not dyn compatible because it uses `Self` as a type parameter
@@ -21,7 +21,7 @@ LL | fn bar(a: &dyn UnsizedConstParamTy) {}
    |                ^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    |
    = note: the trait is not dyn compatible because it uses `Self` as a type parameter
diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr
index 5c8d9c90363..b3605269642 100644
--- a/tests/ui/const-generics/bad-subst-const-kind.stderr
+++ b/tests/ui/const-generics/bad-subst-const-kind.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL | impl<const N: u64> Q for [u8; N] {
    |                          ^^^^^^^ expected `usize`, found `u64`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
 
 error: the constant `13` is not of type `u64`
   --> $DIR/bad-subst-const-kind.rs:13:24
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr
index 763bc626c9d..8bc6ef093d0 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr
@@ -5,7 +5,7 @@ LL | fn use_dyn(v: &dyn Foo) {
    |                ^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-compatibility-err-ret.rs:8:8
    |
 LL | trait Foo {
@@ -24,7 +24,7 @@ LL |     v.test();
    |     ^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-compatibility-err-ret.rs:8:8
    |
 LL | trait Foo {
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr
index 56678e4e9af..f5eaaa37916 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr
@@ -5,7 +5,7 @@ LL | fn use_dyn(v: &dyn Foo) {
    |                ^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8
    |
 LL | trait Foo {
@@ -22,7 +22,7 @@ LL |     v.test();
    |     ^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8
    |
 LL | trait Foo {
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
index bd1811bd2cc..57b61006631 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
@@ -99,7 +99,7 @@ LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
    |                        ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-102768.rs:5:10
    |
 LL | trait X {
diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
index e03580ec007..7cb67252da5 100644
--- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL | impl<const N: u64> Q for [u8; N] {}
    |                          ^^^^^^^ expected `usize`, found `u64`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
 
 error[E0046]: not all trait items implemented, missing: `ASSOC`
   --> $DIR/type_mismatch.rs:8:1
diff --git a/tests/ui/const-generics/issues/index_array_bad_type.rs b/tests/ui/const-generics/issues/index_array_bad_type.rs
new file mode 100644
index 00000000000..91b89cd3fff
--- /dev/null
+++ b/tests/ui/const-generics/issues/index_array_bad_type.rs
@@ -0,0 +1,13 @@
+struct Struct<const N: i128>(pub [u8; N]);
+//~^ ERROR the constant `N` is not of type `usize`
+
+pub fn function(value: Struct<3>) -> u8 {
+    value.0[0]
+    //~^ ERROR the constant `3` is not of type `usize`
+
+    // FIXME(const_generics): Ideally we wouldn't report the above error
+    // b/c `Struct<_>` is never well formed, but I'd rather report too many
+    // errors rather than ICE the compiler.
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/issues/index_array_bad_type.stderr b/tests/ui/const-generics/issues/index_array_bad_type.stderr
new file mode 100644
index 00000000000..ceea0973377
--- /dev/null
+++ b/tests/ui/const-generics/issues/index_array_bad_type.stderr
@@ -0,0 +1,18 @@
+error: the constant `N` is not of type `usize`
+  --> $DIR/index_array_bad_type.rs:1:34
+   |
+LL | struct Struct<const N: i128>(pub [u8; N]);
+   |                                  ^^^^^^^ expected `usize`, found `i128`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
+
+error: the constant `3` is not of type `usize`
+  --> $DIR/index_array_bad_type.rs:5:5
+   |
+LL |     value.0[0]
+   |     ^^^^^^^ expected `usize`, found `i128`
+   |
+   = note: the length of array `[u8; 3]` must be type `usize`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr
index f219c90849a..c497f1b6d0b 100644
--- a/tests/ui/const-generics/issues/issue-88119.stderr
+++ b/tests/ui/const-generics/issues/issue-88119.stderr
@@ -6,35 +6,29 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
    |
    = help: remove one of these features
 
-error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{constant#0}`
-  --> $DIR/issue-88119.rs:19:49
+error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
+  --> $DIR/issue-88119.rs:21:5
    |
-LL | impl<T: ?Sized + ConstName> const ConstName for &T
-   |                                                 ^^ cannot normalize `<&T as ConstName>::{constant#0}`
+LL |     [(); name_len::<T>()]:,
+   |     ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
    |
-note: required for `&T` to implement `~const ConstName`
-  --> $DIR/issue-88119.rs:19:35
+note: required by a bound in `<&T as ConstName>`
+  --> $DIR/issue-88119.rs:21:10
    |
-LL | impl<T: ?Sized + ConstName> const ConstName for &T
-   |                                   ^^^^^^^^^     ^^
-LL | where
 LL |     [(); name_len::<T>()]:,
-   |     --------------------- unsatisfied trait bound introduced here
+   |          ^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>`
 
-error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}`
-  --> $DIR/issue-88119.rs:26:49
+error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
+  --> $DIR/issue-88119.rs:28:5
    |
-LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
-   |                                                 ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}`
+LL |     [(); name_len::<T>()]:,
+   |     ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
    |
-note: required for `&mut T` to implement `~const ConstName`
-  --> $DIR/issue-88119.rs:26:35
+note: required by a bound in `<&mut T as ConstName>`
+  --> $DIR/issue-88119.rs:28:10
    |
-LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
-   |                                   ^^^^^^^^^     ^^^^^^
-LL | where
 LL |     [(); name_len::<T>()]:,
-   |     --------------------- unsatisfied trait bound introduced here
+   |          ^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr
index 978a9744e88..0e26daa3a0f 100644
--- a/tests/ui/const-generics/transmute-fail.stderr
+++ b/tests/ui/const-generics/transmute-fail.stderr
@@ -3,6 +3,8 @@ error: the constant `W` is not of type `usize`
    |
 LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] {
    |                                          ^^^^^^^^^^^^^ expected `usize`, found `bool`
+   |
+   = note: the length of array `[[u32; H]; W]` must be type `usize`
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:11:9
@@ -18,6 +20,8 @@ error: the constant `W` is not of type `usize`
    |
 LL |         std::mem::transmute(v)
    |         ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
+   |
+   = note: the length of array `[[u32; H]; W]` must be type `usize`
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:26:9
diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr
index d1bb5c1242f..bd169ed2ec8 100644
--- a/tests/ui/const-generics/type_mismatch.stderr
+++ b/tests/ui/const-generics/type_mismatch.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL | fn bar<const N: u8>() -> [u8; N] {}
    |                          ^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
 
 error: the constant `N` is not of type `u8`
   --> $DIR/type_mismatch.rs:2:11
diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr
index fad078ad2b2..2e0c04dcf1e 100644
--- a/tests/ui/const-ptr/forbidden_slices.stderr
+++ b/tests/ui/const-ptr/forbidden_slices.stderr
@@ -190,7 +190,7 @@ LL |     from_ptr_range(ptr..ptr.add(1))
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: `ptr_offset_from_unsigned` called on pointers into different allocations
+   = note: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation
    |
 note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -205,7 +205,7 @@ LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).ad
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: `ptr_offset_from_unsigned` called on pointers into different allocations
+   = note: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation
    |
 note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
diff --git a/tests/ui/consts/bad-array-size-in-type-err.rs b/tests/ui/consts/bad-array-size-in-type-err.rs
index cb02ad3205d..0490a9d3620 100644
--- a/tests/ui/consts/bad-array-size-in-type-err.rs
+++ b/tests/ui/consts/bad-array-size-in-type-err.rs
@@ -8,3 +8,14 @@ fn main() {
     //~^ ERROR mismatched types
     //~| ERROR the constant `2` is not of type `usize`
 }
+
+fn iter(val: BadArraySize::<2>) {
+    for _ in val.arr {}
+    //~^ ERROR the constant `2` is not of type `usize`
+    //~| ERROR `[i32; 2]` is not an iterator
+}
+
+// issue #131102
+pub struct Blorb<const N: u16>([String; N]); //~ ERROR the constant `N` is not of type `usize`
+pub struct Wrap(Blorb<0>);
+pub const fn i(_: Wrap) {} //~ ERROR destructor of `Wrap` cannot be evaluated at compile-time
diff --git a/tests/ui/consts/bad-array-size-in-type-err.stderr b/tests/ui/consts/bad-array-size-in-type-err.stderr
index 25d14d80c3e..84e16f8d931 100644
--- a/tests/ui/consts/bad-array-size-in-type-err.stderr
+++ b/tests/ui/consts/bad-array-size-in-type-err.stderr
@@ -3,6 +3,16 @@ error: the constant `N` is not of type `usize`
    |
 LL |     arr: [i32; N],
    |          ^^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[i32; N]` must be type `usize`
+
+error: the constant `N` is not of type `usize`
+  --> $DIR/bad-array-size-in-type-err.rs:19:32
+   |
+LL | pub struct Blorb<const N: u16>([String; N]);
+   |                                ^^^^^^^^^^^ expected `usize`, found `u16`
+   |
+   = note: the length of array `[String; N]` must be type `usize`
 
 error[E0308]: mismatched types
   --> $DIR/bad-array-size-in-type-err.rs:7:38
@@ -15,7 +25,40 @@ error: the constant `2` is not of type `usize`
    |
 LL |     let _ = BadArraySize::<2> { arr: [0, 0, 0] };
    |                                      ^^^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[i32; 2]` must be type `usize`
+
+error: the constant `2` is not of type `usize`
+  --> $DIR/bad-array-size-in-type-err.rs:13:14
+   |
+LL |     for _ in val.arr {}
+   |              ^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[i32; 2]` must be type `usize`
+
+error[E0277]: `[i32; 2]` is not an iterator
+  --> $DIR/bad-array-size-in-type-err.rs:13:14
+   |
+LL |     for _ in val.arr {}
+   |              ^^^^^^^ `[i32; 2]` is not an iterator; try calling `.into_iter()` or `.iter()`
+   |
+   = help: the trait `IntoIterator` is not implemented for `[i32; 2]`
+   = help: the following other types implement trait `IntoIterator`:
+             &[T; N]
+             &[T]
+             &mut [T; N]
+             &mut [T]
+             [T; N]
+
+error[E0493]: destructor of `Wrap` cannot be evaluated at compile-time
+  --> $DIR/bad-array-size-in-type-err.rs:21:16
+   |
+LL | pub const fn i(_: Wrap) {}
+   |                ^         - value is dropped here
+   |                |
+   |                the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 3 previous errors
+error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0277, E0308, E0493.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr
index ec9249ece8e..189d3c3958b 100644
--- a/tests/ui/consts/const-eval/parse_ints.stderr
+++ b/tests/ui/consts/const-eval/parse_ints.stderr
@@ -1,8 +1,10 @@
 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: the evaluated program panicked at 'from_ascii_radix: radix must lie in the range `[2, 36]`', $SRC_DIR/core/src/num/mod.rs:LL:COL
    |
+note: inside `core::num::<impl u64>::from_ascii_radix`
+  --> $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`
@@ -10,13 +12,15 @@ note: inside `_TOO_LOW`
    |
 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)
+   = note: this error originates in the macro `from_str_int_impl` (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: the evaluated program panicked at 'from_ascii_radix: radix must lie in the range `[2, 36]`', $SRC_DIR/core/src/num/mod.rs:LL:COL
    |
+note: inside `core::num::<impl u64>::from_ascii_radix`
+  --> $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`
@@ -24,7 +28,7 @@ note: inside `_TOO_HIGH`
    |
 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)
+   = note: this error originates in the macro `from_str_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/const-slice-array-deref.rs b/tests/ui/consts/const-slice-array-deref.rs
new file mode 100644
index 00000000000..9d84ed4bdb0
--- /dev/null
+++ b/tests/ui/consts/const-slice-array-deref.rs
@@ -0,0 +1,9 @@
+const ONE: [u16] = [1];
+//~^ ERROR the size for values of type `[u16]` cannot be known at compilation time
+//~| ERROR the size for values of type `[u16]` cannot be known at compilation time
+//~| ERROR mismatched types
+
+const TWO: &'static u16 = &ONE[0];
+//~^ ERROR cannot move a value of type `[u16]`
+
+fn main() {}
diff --git a/tests/ui/consts/const-slice-array-deref.stderr b/tests/ui/consts/const-slice-array-deref.stderr
new file mode 100644
index 00000000000..6e69744144e
--- /dev/null
+++ b/tests/ui/consts/const-slice-array-deref.stderr
@@ -0,0 +1,33 @@
+error[E0277]: the size for values of type `[u16]` cannot be known at compilation time
+  --> $DIR/const-slice-array-deref.rs:1:12
+   |
+LL | const ONE: [u16] = [1];
+   |            ^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u16]`
+
+error[E0308]: mismatched types
+  --> $DIR/const-slice-array-deref.rs:1:20
+   |
+LL | const ONE: [u16] = [1];
+   |                    ^^^ expected `[u16]`, found `[u16; 1]`
+
+error[E0277]: the size for values of type `[u16]` cannot be known at compilation time
+  --> $DIR/const-slice-array-deref.rs:1:20
+   |
+LL | const ONE: [u16] = [1];
+   |                    ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u16]`
+   = note: constant expressions must have a statically known size
+
+error[E0161]: cannot move a value of type `[u16]`
+  --> $DIR/const-slice-array-deref.rs:6:28
+   |
+LL | const TWO: &'static u16 = &ONE[0];
+   |                            ^^^ the size of `[u16]` cannot be statically determined
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0161, E0277, E0308.
+For more information about an error, try `rustc --explain E0161`.
diff --git a/tests/ui/consts/large_const_alloc.rs b/tests/ui/consts/large_const_alloc.rs
index 61a22216ae5..14edc1bb696 100644
--- a/tests/ui/consts/large_const_alloc.rs
+++ b/tests/ui/consts/large_const_alloc.rs
@@ -1,5 +1,7 @@
 //@ only-64bit
 // on 32bit and 16bit platforms it is plausible that the maximum allocation size will succeed
+// FIXME (#135952) In some cases on AArch64 Linux the diagnostic does not trigger
+//@ ignore-aarch64-unknown-linux-gnu
 
 const FOO: () = {
     // 128 TiB, unlikely anyone has that much RAM
diff --git a/tests/ui/consts/large_const_alloc.stderr b/tests/ui/consts/large_const_alloc.stderr
index 25d660f1217..fa7d5977a95 100644
--- a/tests/ui/consts/large_const_alloc.stderr
+++ b/tests/ui/consts/large_const_alloc.stderr
@@ -1,11 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/large_const_alloc.rs:6:13
+  --> $DIR/large_const_alloc.rs:8:13
    |
 LL |     let x = [0_u8; (1 << 47) - 1];
    |             ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/large_const_alloc.rs:11:13
+  --> $DIR/large_const_alloc.rs:13:13
    |
 LL |     let x = [0_u8; (1 << 47) - 1];
    |             ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler
diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs
index 0232b03a813..88356900605 100644
--- a/tests/ui/consts/offset_from_ub.rs
+++ b/tests/ui/consts/offset_from_ub.rs
@@ -17,7 +17,7 @@ pub const DIFFERENT_ALLOC: usize = {
     let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
     let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
     let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; //~ERROR evaluation of constant value failed
-    //~| pointers into different allocations
+    //~| not both derived from the same allocation
     offset as usize
 };
 
@@ -37,7 +37,7 @@ pub const DIFFERENT_INT: isize = { // offset_from with two different integers: l
     let ptr1 = 8 as *const u8;
     let ptr2 = 16 as *const u8;
     unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
-    //~| dangling pointer
+    //~| not both derived from the same allocation
 };
 
 const OUT_OF_BOUNDS_1: isize = {
@@ -46,7 +46,7 @@ const OUT_OF_BOUNDS_1: isize = {
     let end_ptr = (start_ptr).wrapping_add(length);
     // First ptr is out of bounds
     unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed
-    //~| expected a pointer to 10 bytes of memory
+    //~| the memory range between them is not in-bounds of an allocation
 };
 
 const OUT_OF_BOUNDS_2: isize = {
@@ -55,7 +55,7 @@ const OUT_OF_BOUNDS_2: isize = {
     let end_ptr = (start_ptr).wrapping_add(length);
     // Second ptr is out of bounds
     unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed
-    //~| expected a pointer to the end of 10 bytes of memory
+    //~| the memory range between them is not in-bounds of an allocation
 };
 
 pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
@@ -64,7 +64,7 @@ pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
     let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
     let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
     unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } //~ERROR evaluation of constant value failed
-    //~| pointers into different allocations
+    //~| not both derived from the same allocation
 };
 
 pub const TOO_FAR_APART1: isize = {
diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr
index ac4597ff011..1379365cc25 100644
--- a/tests/ui/consts/offset_from_ub.stderr
+++ b/tests/ui/consts/offset_from_ub.stderr
@@ -2,12 +2,12 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:19:27
    |
 LL |     let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: `ptr_offset_from` called on pointers into different allocations
+   = note: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
    |
 note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -27,25 +27,25 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:39:14
    |
 LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to $BYTES bytes of memory, but got 0x8[noalloc] which is a dangling pointer (it has no provenance)
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:48:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, start_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to $BYTES bytes of memory, but got ALLOC0 which is only $BYTES bytes from the end of the allocation
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:57:14
    |
 LL |     unsafe { ptr_offset_from(start_ptr, end_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC1+0xa which does not have enough space to the beginning of the allocation
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:66:14
    |
 LL |     unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:73:14
@@ -80,7 +80,7 @@ LL |     unsafe { ptr_offset_from_unsigned(ptr2, ptr1) }
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds `offset_from` origin: expected a pointer to $BYTES bytes of memory, but got a null pointer
+   = note: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
    |
 note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs
index b923a768cbf..53618e2e86a 100644
--- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs
+++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs
@@ -3,6 +3,8 @@
 
 // Needs the max type size to be much bigger than the RAM people typically have.
 //@ only-64bit
+// FIXME (#135952) In some cases on AArch64 Linux the diagnostic does not trigger
+//@ ignore-aarch64-unknown-linux-gnu
 
 pub struct Data([u8; (1 << 47) - 1]);
 const _: &'static Data = &Data([0; (1 << 47) - 1]);
diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr
index f5d767efceb..aac805dbd8c 100644
--- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr
+++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/promoted_running_out_of_memory_issue-130687.rs:8:32
+  --> $DIR/promoted_running_out_of_memory_issue-130687.rs:10:32
    |
 LL | const _: &'static Data = &Data([0; (1 << 47) - 1]);
    |                                ^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler
diff --git a/tests/ui/derives/rustc-decodable-issue-123156.rs b/tests/ui/derives/rustc-decodable-issue-123156.rs
deleted file mode 100644
index 1983837ed8d..00000000000
--- a/tests/ui/derives/rustc-decodable-issue-123156.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ 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
deleted file mode 100644
index 93a993b90d8..00000000000
--- a/tests/ui/derives/rustc-decodable-issue-123156.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-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/diagnostic-width/E0271.ascii.stderr b/tests/ui/diagnostic-width/E0271.ascii.stderr
index 7446b1a543e..93555b336a6 100644
--- a/tests/ui/diagnostic-width/E0271.ascii.stderr
+++ b/tests/ui/diagnostic-width/E0271.ascii.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ...>>, ...>>, ...> as Future>::Error == Foo`
+error[E0271]: type mismatch resolving `<Result<..., ()> as Future>::Error == Foo`
   --> $DIR/E0271.rs:20:5
    |
 LL | /     Box::new(
@@ -7,14 +7,16 @@ LL | |             Err::<(), _>(
 LL | |                 Ok::<_, ()>(
 ...  |
 LL | |     )
-   | |_____^ type mismatch resolving `<Result<Result<(), Result<Result<(), ...>, ...>>, ...> as Future>::Error == Foo`
+   | |_____^ type mismatch resolving `<Result<..., ()> as Future>::Error == Foo`
    |
 note: expected this to be `Foo`
   --> $DIR/E0271.rs:10:18
    |
 LL |     type Error = E;
    |                  ^
-   = note: required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>`
+   = note: required for the cast from `Box<Result<..., ()>>` to `Box<...>`
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271.ascii/E0271.long-type-hash.txt'
+   = note: consider using `--verbose` to print the full type name to the console
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/diagnostic-width/E0271.rs b/tests/ui/diagnostic-width/E0271.rs
index 061ba45c219..2faf09d46c6 100644
--- a/tests/ui/diagnostic-width/E0271.rs
+++ b/tests/ui/diagnostic-width/E0271.rs
@@ -1,6 +1,6 @@
 //@ revisions: ascii unicode
-//@[ascii] compile-flags: --diagnostic-width=40
-//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40
+//@[ascii] compile-flags: --diagnostic-width=40 -Zwrite-long-types-to-disk=yes
+//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40 -Zwrite-long-types-to-disk=yes
 //@ normalize-stderr: "long-type-\d+" -> "long-type-hash"
 trait Future {
     type Error;
diff --git a/tests/ui/diagnostic-width/E0271.unicode.stderr b/tests/ui/diagnostic-width/E0271.unicode.stderr
index 72df2a381a4..1e9acf603b2 100644
--- a/tests/ui/diagnostic-width/E0271.unicode.stderr
+++ b/tests/ui/diagnostic-width/E0271.unicode.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ...>>, ...>>, ...> as Future>::Error == Foo`
+error[E0271]: type mismatch resolving `<Result<..., ()> as Future>::Error == Foo`
    ╭▸ $DIR/E0271.rs:20:5

 LL │ ┏     Box::new(
@@ -7,14 +7,16 @@ LL │ ┃             Err::<(), _>(
 LL │ ┃                 Ok::<_, ()>(
    ‡ ┃
 LL │ ┃     )
-   │ ┗━━━━━┛ type mismatch resolving `<Result<Result<(), Result<Result<(), ...>, ...>>, ...> as Future>::Error == Foo`
+   │ ┗━━━━━┛ type mismatch resolving `<Result<..., ()> as Future>::Error == Foo`
    ╰╴
 note: expected this to be `Foo`
    ╭▸ $DIR/E0271.rs:10:18

 LL │     type Error = E;
    │                  ━
-   ╰ note: required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>`
+   ├ note: required for the cast from `Box<Result<..., ()>>` to `Box<...>`
+   ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271.unicode/E0271.long-type-hash.txt'
+   ╰ note: consider using `--verbose` to print the full type name to the console
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/diagnostic-width/long-E0308.ascii.stderr b/tests/ui/diagnostic-width/long-E0308.ascii.stderr
index d45d6bf329b..83da5586188 100644
--- a/tests/ui/diagnostic-width/long-E0308.ascii.stderr
+++ b/tests/ui/diagnostic-width/long-E0308.ascii.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/long-E0308.rs:46:9
+  --> $DIR/long-E0308.rs:48:9
    |
 LL |        let x: Atype<
    |  _____________-
@@ -16,15 +16,15 @@ LL |  |         Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok...
 LL |  |             Ok("")
 LL |  |         ))))))))))))))))))))))))))))))
 LL |  |     ))))))))))))))))))))))))))))));
-   |  |__________________________________^ expected `Atype<Btype<..., ...>, ...>`, found `Result<Result<..., ...>, ...>`
+   |  |__________________________________^ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `Result<Result<Result<..., _>, _>, _>`
    |
-   = note: expected struct `Atype<Btype<..., ...>, ...>`
-                found enum `Result<Result<..., ...>, ...>`
-   = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt'
+   = note: expected struct `Atype<Btype<..., i32>, i32>`
+                found enum `Result<Result<..., _>, _>`
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    = note: consider using `--verbose` to print the full type name to the console
 
 error[E0308]: mismatched types
-  --> $DIR/long-E0308.rs:59:26
+  --> $DIR/long-E0308.rs:61:26
    |
 LL |       ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O...
    |  __________________________^
@@ -32,15 +32,15 @@ LL | |         Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(...
 LL | |             Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
 LL | |         ))))))))))))))))))))))))))))))
 LL | |     ))))))))))))))))))))))));
-   | |____________________________^ expected `Option<Result<..., ...>>`, found `Result<Result<..., ...>, ...>`
+   | |____________________________^ expected `Option<Result<Option<Option<...>>, _>>`, found `Result<Result<Result<..., _>, _>, _>`
    |
-   = note: expected enum `Option<Result<..., ...>>`
-              found enum `Result<Result<..., ...>, ...>`
-   = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt'
+   = note: expected enum `Option<Result<Option<...>, _>>`
+              found enum `Result<Result<..., _>, _>`
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    = note: consider using `--verbose` to print the full type name to the console
 
 error[E0308]: mismatched types
-  --> $DIR/long-E0308.rs:90:9
+  --> $DIR/long-E0308.rs:92:9
    |
 LL |       let x: Atype<
    |  ____________-
@@ -50,17 +50,17 @@ LL | |           Atype<
 ...  |
 LL | |       i32
 LL | |     > = ();
-   | |     -   ^^ expected `Atype<Btype<..., ...>, ...>`, found `()`
+   | |     -   ^^ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `()`
    | |_____|
    |       expected due to this
    |
-   = note: expected struct `Atype<Btype<..., ...>, ...>`
+   = note: expected struct `Atype<Btype<..., i32>, i32>`
            found unit type `()`
-   = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt'
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    = note: consider using `--verbose` to print the full type name to the console
 
 error[E0308]: mismatched types
-  --> $DIR/long-E0308.rs:93:17
+  --> $DIR/long-E0308.rs:95:17
    |
 LL |       let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O...
    |  ____________--___^
@@ -70,11 +70,11 @@ LL | |         Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(...
 LL | |             Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
 LL | |         ))))))))))))))))))))))))))))))
 LL | |     ))))))))))))))))))))))));
-   | |____________________________^ expected `()`, found `Result<Result<..., ...>, ...>`
+   | |____________________________^ expected `()`, found `Result<Result<Result<..., _>, _>, _>`
    |
    = note: expected unit type `()`
-                   found enum `Result<Result<..., ...>, ...>`
-   = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt'
+                   found enum `Result<Result<..., _>, _>`
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    = note: consider using `--verbose` to print the full type name to the console
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/diagnostic-width/long-E0308.rs b/tests/ui/diagnostic-width/long-E0308.rs
index 93987226020..26383d9418d 100644
--- a/tests/ui/diagnostic-width/long-E0308.rs
+++ b/tests/ui/diagnostic-width/long-E0308.rs
@@ -1,7 +1,9 @@
 //@ revisions: ascii unicode
 //@[ascii] compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes
 //@[unicode] compile-flags: -Zunstable-options --json=diagnostic-unicode --diagnostic-width=60 -Zwrite-long-types-to-disk=yes
-//@ normalize-stderr: "long-type-\d+" -> "long-type-hash"
+
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'"
 
 mod a {
     // Force the "short path for unique types" machinery to trip up
diff --git a/tests/ui/diagnostic-width/long-E0308.unicode.stderr b/tests/ui/diagnostic-width/long-E0308.unicode.stderr
index 3e8d881d7a6..54abf576dbd 100644
--- a/tests/ui/diagnostic-width/long-E0308.unicode.stderr
+++ b/tests/ui/diagnostic-width/long-E0308.unicode.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-   ╭▸ $DIR/long-E0308.rs:46:9
+   ╭▸ $DIR/long-E0308.rs:48:9

 LL │        let x: Atype<
    │ ┌─────────────┘
@@ -16,15 +16,15 @@ LL │  ┃         Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O…
 LL │  ┃             Ok("")
 LL │  ┃         ))))))))))))))))))))))))))))))
 LL │  ┃     ))))))))))))))))))))))))))))));
-   │  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype<Btype<..., ...>, ...>`, found `Result<Result<..., ...>, ...>`
+   │  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `Result<Result<Result<..., _>, _>, _>`

-   ├ note: expected struct `Atype<Btype<..., ...>, ...>`
-   │            found enum `Result<Result<..., ...>, ...>`
-   ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt'
+   ├ note: expected struct `Atype<Btype<..., i32>, i32>`
+   │            found enum `Result<Result<..., _>, _>`
+   ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    ╰ note: consider using `--verbose` to print the full type name to the console
 
 error[E0308]: mismatched types
-   ╭▸ $DIR/long-E0308.rs:59:26
+   ╭▸ $DIR/long-E0308.rs:61:26

 LL │       ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(…
    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┛
@@ -32,15 +32,15 @@ LL │ ┃         Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok…
 LL │ ┃             Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
 LL │ ┃         ))))))))))))))))))))))))))))))
 LL │ ┃     ))))))))))))))))))))))));
-   │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option<Result<..., ...>>`, found `Result<Result<..., ...>, ...>`
+   │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option<Result<Option<Option<...>>, _>>`, found `Result<Result<Result<..., _>, _>, _>`

-   ├ note: expected enum `Option<Result<..., ...>>`
-   │          found enum `Result<Result<..., ...>, ...>`
-   ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt'
+   ├ note: expected enum `Option<Result<Option<...>, _>>`
+   │          found enum `Result<Result<..., _>, _>`
+   ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    ╰ note: consider using `--verbose` to print the full type name to the console
 
 error[E0308]: mismatched types
-   ╭▸ $DIR/long-E0308.rs:90:9
+   ╭▸ $DIR/long-E0308.rs:92:9

 LL │       let x: Atype<
    │ ┌────────────┘
@@ -50,17 +50,17 @@ LL │ │           Atype<
    ‡ │
 LL │ │       i32
 LL │ │     > = ();
-   │ │     │   ━━ expected `Atype<Btype<..., ...>, ...>`, found `()`
+   │ │     │   ━━ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `()`
    │ └─────┤
    │       expected due to this

-   ├ note: expected struct `Atype<Btype<..., ...>, ...>`
+   ├ note: expected struct `Atype<Btype<..., i32>, i32>`
    │       found unit type `()`
-   ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt'
+   ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    ╰ note: consider using `--verbose` to print the full type name to the console
 
 error[E0308]: mismatched types
-   ╭▸ $DIR/long-E0308.rs:93:17
+   ╭▸ $DIR/long-E0308.rs:95:17

 LL │       let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(…
    │ ┏━━━━━━━━━━━━┬─━━━┛
@@ -70,11 +70,11 @@ LL │ ┃         Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok…
 LL │ ┃             Ok(Ok(Ok(Ok(Ok(Ok(Ok("")))))))
 LL │ ┃         ))))))))))))))))))))))))))))))
 LL │ ┃     ))))))))))))))))))))))));
-   │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result<Result<..., ...>, ...>`
+   │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result<Result<Result<..., _>, _>, _>`

    ├ note: expected unit type `()`
-   │               found enum `Result<Result<..., ...>, ...>`
-   ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt'
+   │               found enum `Result<Result<..., _>, _>`
+   ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    ╰ note: consider using `--verbose` to print the full type name to the console
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/diagnostic-width/long-e0277.rs b/tests/ui/diagnostic-width/long-e0277.rs
new file mode 100644
index 00000000000..9b3bd8bb728
--- /dev/null
+++ b/tests/ui/diagnostic-width/long-e0277.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'"
+type A = (i32, i32, i32, i32);
+type B = (A, A, A, A);
+type C = (B, B, B, B);
+type D = (C, C, C, C);
+
+trait Trait {}
+
+fn require_trait<T: Trait>() {}
+
+fn main() {
+    require_trait::<D>(); //~ ERROR the trait bound `(...
+}
diff --git a/tests/ui/diagnostic-width/long-e0277.stderr b/tests/ui/diagnostic-width/long-e0277.stderr
new file mode 100644
index 00000000000..a57270df7e2
--- /dev/null
+++ b/tests/ui/diagnostic-width/long-e0277.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `(..., ..., ..., ...): Trait` is not satisfied
+  --> $DIR/long-e0277.rs:14:21
+   |
+LL |     require_trait::<D>();
+   |                     ^ unsatisfied trait bound
+   |
+   = help: the trait `Trait` is not implemented for `(..., ..., ..., ...)`
+help: this trait has no implementations, consider adding one
+  --> $DIR/long-e0277.rs:9:1
+   |
+LL | trait Trait {}
+   | ^^^^^^^^^^^
+note: required by a bound in `require_trait`
+  --> $DIR/long-e0277.rs:11:21
+   |
+LL | fn require_trait<T: Trait>() {}
+   |                     ^^^^^ required by this bound in `require_trait`
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
+   = note: consider using `--verbose` to print the full type name to the console
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic-width/non-copy-type-moved.rs b/tests/ui/diagnostic-width/non-copy-type-moved.rs
index a5593ad7b2a..a220c62775e 100644
--- a/tests/ui/diagnostic-width/non-copy-type-moved.rs
+++ b/tests/ui/diagnostic-width/non-copy-type-moved.rs
@@ -1,5 +1,7 @@
 //@ compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes
-//@ normalize-stderr: "long-type-\d+" -> "long-type-hash"
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'"
+
 type A = (String, String, String, String);
 type B = (A, A, A, A);
 type C = (B, B, B, B);
diff --git a/tests/ui/diagnostic-width/non-copy-type-moved.stderr b/tests/ui/diagnostic-width/non-copy-type-moved.stderr
index da9385a5b4d..254542c7b39 100644
--- a/tests/ui/diagnostic-width/non-copy-type-moved.stderr
+++ b/tests/ui/diagnostic-width/non-copy-type-moved.stderr
@@ -1,14 +1,14 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/non-copy-type-moved.rs:14:14
+  --> $DIR/non-copy-type-moved.rs:16:14
    |
 LL | fn foo(x: D) {
-   |        - move occurs because `x` has type `((..., ..., ..., ...), ..., ..., ...)`, which does not implement the `Copy` trait
+   |        - move occurs because `x` has type `(..., ..., ..., ...)`, which does not implement the `Copy` trait
 LL |     let _a = x;
    |              - value moved here
 LL |     let _b = x;
    |              ^ value used here after move
    |
-   = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/non-copy-type-moved/non-copy-type-moved.long-type-hash.txt'
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    = note: consider using `--verbose` to print the full type name to the console
 help: consider cloning the value if the performance cost is acceptable
    |
diff --git a/tests/ui/diagnostic-width/secondary-label-with-long-type.rs b/tests/ui/diagnostic-width/secondary-label-with-long-type.rs
index 6ed600c48ac..c8845af3183 100644
--- a/tests/ui/diagnostic-width/secondary-label-with-long-type.rs
+++ b/tests/ui/diagnostic-width/secondary-label-with-long-type.rs
@@ -1,5 +1,7 @@
 //@ compile-flags: --diagnostic-width=100 -Zwrite-long-types-to-disk=yes
-//@ normalize-stderr: "long-type-\d+" -> "long-type-hash"
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'"
+
 type A = (i32, i32, i32, i32);
 type B = (A, A, A, A);
 type C = (B, B, B, B);
@@ -10,7 +12,7 @@ fn foo(x: D) {
     //~^ NOTE this expression has type `((...,
     //~| NOTE expected `((...,
     //~| NOTE expected tuple
-    //~| NOTE the full type name has been written to
+    //~| NOTE the full name for the type has been written to
     //~| NOTE consider using `--verbose` to print the full type name to the console
 }
 
diff --git a/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr b/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr
index 1e890455156..a95e1709148 100644
--- a/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr
+++ b/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/secondary-label-with-long-type.rs:9:9
+  --> $DIR/secondary-label-with-long-type.rs:11:9
    |
 LL |     let () = x;
    |         ^^   - this expression has type `((..., ..., ..., ...), ..., ..., ...)`
@@ -8,7 +8,7 @@ LL |     let () = x;
    |
    = note:  expected tuple `((..., ..., ..., ...), ..., ..., ...)`
            found unit type `()`
-   = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/secondary-label-with-long-type/secondary-label-with-long-type.long-type-hash.txt'
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    = note: consider using `--verbose` to print the full type name to the console
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
index 1b76669ccb0..4f685c508c7 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
@@ -16,23 +16,13 @@ LL |     where
 LL |         T: AsExpression<Self::SqlType>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
 
-error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
-  --> $DIR/as_expression.rs:55:15
-   |
-LL |     SelectInt.check("bar");
-   |               ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
-   |
-   = help: the trait `AsExpression<Integer>` is not implemented for `&str`
-           but trait `AsExpression<Text>` is implemented for it
-   = help: for that trait implementation, expected `Text`, found `Integer`
-
 error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text`
   --> $DIR/as_expression.rs:55:5
    |
 LL |     SelectInt.check("bar");
    |     ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0271, E0277.
 For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
index 583b3c4675a..48c1ed2b02d 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
@@ -53,7 +53,7 @@ impl<T> Foo for T where T: Expression {}
 
 fn main() {
     SelectInt.check("bar");
-    //~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
-    //[next]~| the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
+    //[current]~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
+    //[next]~^^ the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
     //[next]~| type mismatch
 }
diff --git a/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs b/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs
new file mode 100644
index 00000000000..fa1663d49eb
--- /dev/null
+++ b/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs
@@ -0,0 +1,9 @@
+//@ edition: 2021
+
+fn foo() {}
+
+fn main() {
+    let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect(); //~ ERROR
+    let _: Vec<fn()> = [foo].into_iter().collect(); //~ ERROR
+    let _: Vec<fn()> = Vec::from([foo]); //~ ERROR
+}
diff --git a/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr b/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr
new file mode 100644
index 00000000000..d069d39514d
--- /dev/null
+++ b/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr
@@ -0,0 +1,59 @@
+error[E0277]: a value of type `Vec<(&str, fn())>` cannot be built from an iterator over elements of type `(&str, fn() {foo})`
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:6:59
+   |
+LL |     let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect();
+   |                                                           ^^^^^^^ value of type `Vec<(&str, fn())>` cannot be built from `std::iter::Iterator<Item=(&str, fn() {foo})>`
+   |
+   = help: the trait `FromIterator<(&_, fn() {foo})>` is not implemented for `Vec<(&str, fn())>`
+           but trait `FromIterator<(&_, fn())>` is implemented for it
+   = help: for that trait implementation, expected `fn()`, found `fn() {foo}`
+   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `foo as fn()`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:6:47
+   |
+LL |     let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect();
+   |                                -------------- ^^^^^^^^^^^ `Iterator::Item` is `(&str, fn() {foo})` here
+   |                                |
+   |                                this expression has type `[(&str, fn() {foo}); 1]`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0277]: a value of type `Vec<fn()>` cannot be built from an iterator over elements of type `fn() {foo}`
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:7:42
+   |
+LL |     let _: Vec<fn()> = [foo].into_iter().collect();
+   |                                          ^^^^^^^ value of type `Vec<fn()>` cannot be built from `std::iter::Iterator<Item=fn() {foo}>`
+   |
+   = help: the trait `FromIterator<fn() {foo}>` is not implemented for `Vec<fn()>`
+           but trait `FromIterator<fn()>` is implemented for it
+   = help: for that trait implementation, expected `fn()`, found `fn() {foo}`
+   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `foo as fn()`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:7:30
+   |
+LL |     let _: Vec<fn()> = [foo].into_iter().collect();
+   |                        ----- ^^^^^^^^^^^ `Iterator::Item` is `fn() {foo}` here
+   |                        |
+   |                        this expression has type `[fn() {foo}; 1]`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0308]: mismatched types
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:8:24
+   |
+LL |     let _: Vec<fn()> = Vec::from([foo]);
+   |            ---------   ^^^^^^^^^^^^^^^^ expected `Vec<fn()>`, found `Vec<fn() {foo}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `Vec<fn()>`
+              found struct `Vec<fn() {foo}>`
+   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `foo as fn()`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/did_you_mean/issue-38147-1.stderr b/tests/ui/did_you_mean/issue-38147-1.stderr
index a0392113ab1..6def86e4ba8 100644
--- a/tests/ui/did_you_mean/issue-38147-1.stderr
+++ b/tests/ui/did_you_mean/issue-38147-1.stderr
@@ -7,7 +7,7 @@ LL |         self.s.push('x');
 help: consider changing this to be a mutable reference
    |
 LL |     fn f(&mut self) {
-   |          ~~~~~~~~~
+   |           +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/did_you_mean/issue-39544.stderr b/tests/ui/did_you_mean/issue-39544.stderr
index 8ccb4cbb0c1..62dc027e31f 100644
--- a/tests/ui/did_you_mean/issue-39544.stderr
+++ b/tests/ui/did_you_mean/issue-39544.stderr
@@ -18,7 +18,7 @@ LL |         let _ = &mut self.x;
 help: consider changing this to be a mutable reference
    |
 LL |     fn foo<'z>(&'z mut self) {
-   |                ~~~~~~~~~~~~
+   |                    +++
 
 error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:20:17
@@ -29,7 +29,7 @@ LL |         let _ = &mut self.x;
 help: consider changing this to be a mutable reference
    |
 LL |     fn foo1(&mut self, other: &Z) {
-   |             ~~~~~~~~~
+   |              +++
 
 error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:21:17
@@ -51,7 +51,7 @@ LL |         let _ = &mut self.x;
 help: consider changing this to be a mutable reference
    |
 LL |     fn foo2<'a>(&'a mut self, other: &Z) {
-   |                 ~~~~~~~~~~~~
+   |                     +++
 
 error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:26:17
diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
index 7994ddf11c3..4fee6cc9a22 100644
--- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
+++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
@@ -28,7 +28,7 @@ LL |     let _: &Copy + 'static;
    |
    = note: the trait is not dyn compatible because it requires `Self: Sized`
    = note: for a trait to be dyn compatible it needs to allow building a vtable
-           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr
index f241333f2a7..a384697ee08 100644
--- a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr
+++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr
@@ -5,7 +5,7 @@ LL | impl<T, U> Dyn for dyn Foo<T, U> + '_ {
    |                    ^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/almost-supertrait-associated-type.rs:33:34
    |
 LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
@@ -22,7 +22,7 @@ LL |     (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
    |                           ^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/almost-supertrait-associated-type.rs:33:34
    |
 LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
@@ -39,7 +39,7 @@ LL |     (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
    |      ^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/almost-supertrait-associated-type.rs:33:34
    |
 LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
diff --git a/tests/ui/dyn-compatibility/associated-consts.curr.stderr b/tests/ui/dyn-compatibility/associated-consts.curr.stderr
index 45d4f795542..de243938123 100644
--- a/tests/ui/dyn-compatibility/associated-consts.curr.stderr
+++ b/tests/ui/dyn-compatibility/associated-consts.curr.stderr
@@ -5,7 +5,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    |                               ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/associated-consts.rs:9:11
    |
 LL | trait Bar {
@@ -21,7 +21,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/associated-consts.rs:9:11
    |
 LL | trait Bar {
diff --git a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr
index 4c8c82196ed..704d833f00b 100644
--- a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr
@@ -5,7 +5,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/associated-consts.rs:9:11
    |
 LL | trait Bar {
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
index ff5e9fdb6b3..b811ef40c26 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr
@@ -34,7 +34,7 @@ LL | fn id<F>(f: Copy) -> usize {
    |
    = note: the trait is not dyn compatible because it requires `Self: Sized`
    = note: for a trait to be dyn compatible it needs to allow building a vtable
-           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
 
 error[E0618]: expected function, found `(dyn Copy + 'static)`
   --> $DIR/avoid-ice-on-warning-2.rs:12:5
diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
index 92a2d340115..d8935be5609 100644
--- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
+++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr
@@ -72,7 +72,7 @@ LL | trait B { fn f(a: A) -> A; }
    |                   ^ `A` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/avoid-ice-on-warning-3.rs:14:14
    |
 LL | trait A { fn g(b: B) -> B; }
@@ -109,7 +109,7 @@ LL | trait A { fn g(b: B) -> B; }
    |                   ^ `B` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/avoid-ice-on-warning-3.rs:4:14
    |
 LL | trait B { fn f(a: A) -> A; }
diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr
index e3ec5b9c3c8..7be6cb0d03b 100644
--- a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr
+++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr
@@ -23,7 +23,7 @@ LL | fn ord_prefer_dot(s: String) -> Ord {
    |                                 ^^^ `Ord` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    |
    = note: the trait is not dyn compatible because it uses `Self` as a type parameter
diff --git a/tests/ui/dyn-compatibility/bounds.stderr b/tests/ui/dyn-compatibility/bounds.stderr
index d45e66b1d5e..5473af388c0 100644
--- a/tests/ui/dyn-compatibility/bounds.stderr
+++ b/tests/ui/dyn-compatibility/bounds.stderr
@@ -5,7 +5,7 @@ LL | fn f() -> Box<dyn X<U = u32>> {
    |               ^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/bounds.rs:4:13
    |
 LL | trait X {
diff --git a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr
index 04dc0b1d6f4..cfebd5d6947 100644
--- a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr
+++ b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr
@@ -5,7 +5,7 @@ LL | fn take_dyn(_: &dyn Child) {}
    |                     ^^^^^ `Super` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/gat-incompatible-supertrait.rs:10:10
    |
 LL | trait Super {
diff --git a/tests/ui/dyn-compatibility/generics.curr.stderr b/tests/ui/dyn-compatibility/generics.curr.stderr
index 1607954ab70..d29d02b2ff3 100644
--- a/tests/ui/dyn-compatibility/generics.curr.stderr
+++ b/tests/ui/dyn-compatibility/generics.curr.stderr
@@ -5,7 +5,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    |                               ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
@@ -21,7 +21,7 @@ LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
    |                                        ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
@@ -37,7 +37,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
@@ -54,7 +54,7 @@ LL |     t as &dyn Bar
    |          ^^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
@@ -70,7 +70,7 @@ LL |     t as &dyn Bar
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
diff --git a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr
index 7f31b29b39c..b3565a766fe 100644
--- a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr
@@ -5,7 +5,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
@@ -22,7 +22,7 @@ LL |     t as &dyn Bar
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/generics.rs:10:8
    |
 LL | trait Bar {
diff --git a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr
index 1ed78e1e659..bb3f7899bf1 100644
--- a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr
+++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr
@@ -5,7 +5,7 @@ LL |     let test: &mut dyn Bar = &mut thing;
    |               ^^^^^^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8
    |
 LL |     fn foo<T>(&self, val: T);
@@ -23,7 +23,7 @@ LL |     let test: &mut dyn Bar = &mut thing;
    |                              ^^^^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8
    |
 LL |     fn foo<T>(&self, val: T);
diff --git a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr
index eba2c15dd74..cf3a7b23084 100644
--- a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr
+++ b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr
@@ -5,7 +5,7 @@ LL |     elements: Vec<Box<dyn Expr + 'x>>,
    |                           ^^^^ `Expr` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mentions-Self-in-super-predicates.rs:5:21
    |
 LL | trait Expr: Debug + PartialEq {
@@ -20,7 +20,7 @@ LL |     let a: Box<dyn Expr> = Box::new(SExpr::new());
    |                    ^^^^ `Expr` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mentions-Self-in-super-predicates.rs:5:21
    |
 LL | trait Expr: Debug + PartialEq {
@@ -35,7 +35,7 @@ LL |     let b: Box<dyn Expr> = Box::new(SExpr::new());
    |                    ^^^^ `Expr` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mentions-Self-in-super-predicates.rs:5:21
    |
 LL | trait Expr: Debug + PartialEq {
diff --git a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr
index 90db86ffef9..2d3fe5ce636 100644
--- a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr
+++ b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr
@@ -5,7 +5,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    |                               ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mentions-Self.rs:11:22
    |
 LL | trait Bar {
@@ -21,7 +21,7 @@ LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
    |                               ^^^^^^^ `Baz` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mentions-Self.rs:15:22
    |
 LL | trait Baz {
@@ -37,7 +37,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mentions-Self.rs:11:22
    |
 LL | trait Bar {
@@ -54,7 +54,7 @@ LL |     t
    |     ^ `Baz` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mentions-Self.rs:15:22
    |
 LL | trait Baz {
diff --git a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr
index 4a50d3f07e4..91c26a86025 100644
--- a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr
@@ -5,7 +5,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mentions-Self.rs:11:22
    |
 LL | trait Bar {
@@ -22,7 +22,7 @@ LL |     t
    |     ^ `Baz` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/mentions-Self.rs:15:22
    |
 LL | trait Baz {
diff --git a/tests/ui/dyn-compatibility/missing-assoc-type.stderr b/tests/ui/dyn-compatibility/missing-assoc-type.stderr
index 3f550494b33..5a7560682f2 100644
--- a/tests/ui/dyn-compatibility/missing-assoc-type.stderr
+++ b/tests/ui/dyn-compatibility/missing-assoc-type.stderr
@@ -5,7 +5,7 @@ LL | fn bar(x: &dyn Foo) {}
    |                ^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/missing-assoc-type.rs:2:10
    |
 LL | trait Foo {
diff --git a/tests/ui/dyn-compatibility/no-static.curr.stderr b/tests/ui/dyn-compatibility/no-static.curr.stderr
index 867c485053d..bf9b48e7a43 100644
--- a/tests/ui/dyn-compatibility/no-static.curr.stderr
+++ b/tests/ui/dyn-compatibility/no-static.curr.stderr
@@ -5,7 +5,7 @@ LL | fn diverges() -> Box<dyn Foo> {
    |                      ^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/no-static.rs:9:8
    |
 LL | trait Foo {
@@ -29,7 +29,7 @@ LL |     let b: Box<dyn Foo> = Box::new(Bar);
    |            ^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/no-static.rs:9:8
    |
 LL | trait Foo {
@@ -53,7 +53,7 @@ LL |     let b: Box<dyn Foo> = Box::new(Bar);
    |                           ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/no-static.rs:9:8
    |
 LL | trait Foo {
diff --git a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr
index 65608a9cca7..d5ad4510334 100644
--- a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr
@@ -5,7 +5,7 @@ LL |     let b: Box<dyn Foo> = Box::new(Bar);
    |                           ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/no-static.rs:9:8
    |
 LL | trait Foo {
diff --git a/tests/ui/dyn-compatibility/sized-2.curr.stderr b/tests/ui/dyn-compatibility/sized-2.curr.stderr
index c8fd1056237..2d262072d5d 100644
--- a/tests/ui/dyn-compatibility/sized-2.curr.stderr
+++ b/tests/ui/dyn-compatibility/sized-2.curr.stderr
@@ -5,7 +5,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    |                               ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/sized-2.rs:9:18
    |
 LL | trait Bar
@@ -20,7 +20,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/sized-2.rs:9:18
    |
 LL | trait Bar
diff --git a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr
index 477dacdf5a1..1fbc10c0c3f 100644
--- a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr
@@ -5,7 +5,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/sized-2.rs:9:18
    |
 LL | trait Bar
diff --git a/tests/ui/dyn-compatibility/sized.curr.stderr b/tests/ui/dyn-compatibility/sized.curr.stderr
index d86ea9197b9..a197d967005 100644
--- a/tests/ui/dyn-compatibility/sized.curr.stderr
+++ b/tests/ui/dyn-compatibility/sized.curr.stderr
@@ -5,7 +5,7 @@ LL | fn make_bar<T: Bar>(t: &T) -> &dyn Bar {
    |                                ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/sized.rs:8:12
    |
 LL | trait Bar: Sized {
@@ -20,7 +20,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/sized.rs:8:12
    |
 LL | trait Bar: Sized {
diff --git a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr
index b763173594b..350c8992c6f 100644
--- a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr
@@ -5,7 +5,7 @@ LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/sized.rs:8:12
    |
 LL | trait Bar: Sized {
diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr
index f5dea256469..8e139ee6b48 100644
--- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr
+++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr
@@ -27,7 +27,7 @@ LL |     fn c(&self) -> dyn SuperTrait<T>;
    |                    ^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/supertrait-mentions-GAT.rs:4:10
    |
 LL |     type Gat<'a>
diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr
index f9ef0c9b2e0..a763649e9c6 100644
--- a/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr
+++ b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr
@@ -25,7 +25,7 @@ LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
    |                                   ^^^ `Baz` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/supertrait-mentions-Self.rs:8:13
    |
 LL | trait Baz : Bar<Self> {
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr b/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr
index 8442314835e..7e80a1d2e42 100644
--- a/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr
+++ b/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr
@@ -5,7 +5,7 @@ LL | static FOO: &(dyn Qux + Sync) = "desc";
    |               ^^^^^^^^^^^^^^ `Qux` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/taint-const-eval.rs:8:8
    |
 LL | trait Qux {
@@ -28,7 +28,7 @@ LL | static FOO: &(dyn Qux + Sync) = "desc";
    |                                 ^^^^^^ `Qux` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/taint-const-eval.rs:8:8
    |
 LL | trait Qux {
@@ -52,7 +52,7 @@ LL | static FOO: &(dyn Qux + Sync) = "desc";
    |               ^^^^^^^^^^^^^^ `Qux` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/taint-const-eval.rs:8:8
    |
 LL | trait Qux {
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr
index 1c51df8501f..0bc7d0b14d3 100644
--- a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr
@@ -5,7 +5,7 @@ LL | static FOO: &(dyn Qux + Sync) = "desc";
    |                                 ^^^^^^ `Qux` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/taint-const-eval.rs:8:8
    |
 LL | trait Qux {
diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr
index 45a924008c7..1299167159e 100644
--- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr
+++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr
@@ -8,7 +8,7 @@ LL | fn fetcher() -> Box<dyn Fetcher> {
    |                     ^^^^^^^^^^^ `Fetcher` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22
    |
 LL | pub trait Fetcher: Send + Sync {
@@ -26,7 +26,7 @@ LL |     let fetcher = fetcher();
    |                   ^^^^^^^^^ `Fetcher` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22
    |
 LL | pub trait Fetcher: Send + Sync {
@@ -44,7 +44,7 @@ LL |     let _ = fetcher.get();
    |             ^^^^^^^^^^^^^ `Fetcher` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22
    |
 LL | pub trait Fetcher: Send + Sync {
diff --git a/tests/ui/error-codes/E0038.stderr b/tests/ui/error-codes/E0038.stderr
index 59e9f504d17..63a5249a386 100644
--- a/tests/ui/error-codes/E0038.stderr
+++ b/tests/ui/error-codes/E0038.stderr
@@ -5,7 +5,7 @@ LL | fn call_foo(x: Box<dyn Trait>) {
    |                    ^^^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/E0038.rs:2:22
    |
 LL | trait Trait {
@@ -21,7 +21,7 @@ LL |     let y = x.foo();
    |             ^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/E0038.rs:2:22
    |
 LL | trait Trait {
diff --git a/tests/ui/error-codes/E0789.rs b/tests/ui/error-codes/E0789.rs
index 3acc983edc4..08471e1b3f3 100644
--- a/tests/ui/error-codes/E0789.rs
+++ b/tests/ui/error-codes/E0789.rs
@@ -4,7 +4,7 @@
 #![feature(staged_api)]
 #![unstable(feature = "foo_module", reason = "...", issue = "123")]
 
-#[rustc_allowed_through_unstable_modules]
+#[rustc_allowed_through_unstable_modules = "use stable path instead"]
 // #[stable(feature = "foo", since = "1.0")]
 struct Foo;
 //~^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
diff --git a/tests/ui/error-emitter/E0308-clarification.rs b/tests/ui/error-emitter/E0308-clarification.rs
new file mode 100644
index 00000000000..4c15ede0041
--- /dev/null
+++ b/tests/ui/error-emitter/E0308-clarification.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Zunstable-options --error-format=human-unicode --color=always
+//@ only-linux
+// Ensure that when we have a type error where both types have the same textual representation, the
+// diagnostic machinery highlights the clarifying comment that comes after in parentheses.
+trait Foo: Copy + ToString {}
+
+impl<T: Copy + ToString> Foo for T {}
+
+fn hide<T: Foo>(x: T) -> impl Foo {
+    x
+}
+
+fn main() {
+    let mut x = (hide(0_u32), hide(0_i32));
+    x = (x.1, x.0);
+}
diff --git a/tests/ui/error-emitter/E0308-clarification.svg b/tests/ui/error-emitter/E0308-clarification.svg
new file mode 100644
index 00000000000..9432e3a4ee9
--- /dev/null
+++ b/tests/ui/error-emitter/E0308-clarification.svg
@@ -0,0 +1,97 @@
+<svg width="740px" height="668px" xmlns="http://www.w3.org/2000/svg">
+  <style>
+    .fg { fill: #AAAAAA }
+    .bg { background: #000000 }
+    .fg-ansi256-009 { fill: #FF5555 }
+    .fg-ansi256-012 { fill: #5555FF }
+    .fg-magenta { fill: #AA00AA }
+    .container {
+      padding: 0 10px;
+      line-height: 18px;
+    }
+    .bold { font-weight: bold; }
+    tspan {
+      font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+      white-space: pre;
+      line-height: 18px;
+    }
+  </style>
+
+  <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+  <text xml:space="preserve" class="container fg">
+    <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="bold">: mismatched types</tspan>
+</tspan>
+    <tspan x="10px" y="46px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold"> ╭▸ </tspan><tspan>$DIR/E0308-clarification.rs:15:10</tspan>
+</tspan>
+    <tspan x="10px" y="64px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
+</tspan>
+    <tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> fn hide&lt;T: Foo&gt;(x: T) -&gt; impl Foo {</tspan>
+</tspan>
+    <tspan x="10px" y="100px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>                          </tspan><tspan class="fg-ansi256-012 bold">┬───────</tspan>
+</tspan>
+    <tspan x="10px" y="118px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>                          </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
+</tspan>
+    <tspan x="10px" y="136px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>                          </tspan><tspan class="fg-ansi256-012 bold">the expected opaque type</tspan>
+</tspan>
+    <tspan x="10px" y="154px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>                          </tspan><tspan class="fg-ansi256-012 bold">the found opaque type</tspan>
+</tspan>
+    <tspan x="10px" y="172px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">‡</tspan>
+</tspan>
+    <tspan x="10px" y="190px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>     x = (x.1, x.0);</tspan>
+</tspan>
+    <tspan x="10px" y="208px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>          </tspan><tspan class="fg-ansi256-009 bold">━━━</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">expected `u32`, found `i32`</tspan>
+</tspan>
+    <tspan x="10px" y="226px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
+</tspan>
+    <tspan x="10px" y="244px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">├ </tspan><tspan class="bold">note</tspan><tspan>: expected opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`u32`</tspan><tspan>)</tspan>
+</tspan>
+    <tspan x="10px" y="262px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>          found opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`i32`</tspan><tspan>)</tspan>
+</tspan>
+    <tspan x="10px" y="280px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">╰ </tspan><tspan class="bold">note</tspan><tspan>: distinct uses of `impl Trait` result in different opaque types</tspan>
+</tspan>
+    <tspan x="10px" y="298px">
+</tspan>
+    <tspan x="10px" y="316px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="bold">: mismatched types</tspan>
+</tspan>
+    <tspan x="10px" y="334px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold"> ╭▸ </tspan><tspan>$DIR/E0308-clarification.rs:15:15</tspan>
+</tspan>
+    <tspan x="10px" y="352px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
+</tspan>
+    <tspan x="10px" y="370px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> fn hide&lt;T: Foo&gt;(x: T) -&gt; impl Foo {</tspan>
+</tspan>
+    <tspan x="10px" y="388px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>                          </tspan><tspan class="fg-ansi256-012 bold">┬───────</tspan>
+</tspan>
+    <tspan x="10px" y="406px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>                          </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
+</tspan>
+    <tspan x="10px" y="424px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>                          </tspan><tspan class="fg-ansi256-012 bold">the expected opaque type</tspan>
+</tspan>
+    <tspan x="10px" y="442px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>                          </tspan><tspan class="fg-ansi256-012 bold">the found opaque type</tspan>
+</tspan>
+    <tspan x="10px" y="460px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">‡</tspan>
+</tspan>
+    <tspan x="10px" y="478px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>     x = (x.1, x.0);</tspan>
+</tspan>
+    <tspan x="10px" y="496px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>               </tspan><tspan class="fg-ansi256-009 bold">━━━</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">expected `i32`, found `u32`</tspan>
+</tspan>
+    <tspan x="10px" y="514px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan>
+</tspan>
+    <tspan x="10px" y="532px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">├ </tspan><tspan class="bold">note</tspan><tspan>: expected opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`i32`</tspan><tspan>)</tspan>
+</tspan>
+    <tspan x="10px" y="550px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan>          found opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`u32`</tspan><tspan>)</tspan>
+</tspan>
+    <tspan x="10px" y="568px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">╰ </tspan><tspan class="bold">note</tspan><tspan>: distinct uses of `impl Trait` result in different opaque types</tspan>
+</tspan>
+    <tspan x="10px" y="586px">
+</tspan>
+    <tspan x="10px" y="604px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 2 previous errors</tspan>
+</tspan>
+    <tspan x="10px" y="622px">
+</tspan>
+    <tspan x="10px" y="640px"><tspan class="bold">For more information about this error, try `rustc --explain E0308`.</tspan>
+</tspan>
+    <tspan x="10px" y="658px">
+</tspan>
+  </text>
+
+</svg>
diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr
index b4de6b66469..ab8c092a826 100644
--- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr
+++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr
@@ -5,7 +5,7 @@ LL | async fn takes_dyn_trait(x: &dyn Foo) {
    |                              ^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
    |
 LL | trait Foo {
@@ -21,7 +21,7 @@ LL |     x.bar().await;
    |       ^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
    |
 LL | trait Foo {
@@ -37,7 +37,7 @@ LL |     x.bar().await;
    |     ^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
    |
 LL | trait Foo {
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr
index f8fc086c441..6634ce12118 100644
--- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr
+++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr
@@ -8,7 +8,7 @@ LL |     Ptr(Box::new(4)) as Ptr<dyn Trait>;
    |                         ^^^^^^^^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
    |
 LL | trait Trait {
@@ -27,7 +27,7 @@ LL |     Ptr(Box::new(4)) as Ptr<dyn Trait>;
    |     ^^^^^^^^^^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
    |
 LL | trait Trait {
diff --git a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr
index 10540f0219d..2c3edd6e6a5 100644
--- a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr
@@ -5,7 +5,7 @@ LL | fn takes_dyn_incompatible_ref<T>(obj: &dyn DynIncompatible1) {
    |                                        ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25
    |
 LL | trait DynIncompatible1: Sized {}
@@ -20,7 +20,7 @@ LL | fn return_dyn_incompatible_ref() -> &'static dyn DynIncompatible2 {
    |                                              ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible2` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:7:8
    |
 LL | trait DynIncompatible2 {
@@ -43,7 +43,7 @@ LL | fn takes_dyn_incompatible_box(obj: Box<dyn DynIncompatible3>) {
    |                                        ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible3` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:11:8
    |
 LL | trait DynIncompatible3 {
@@ -59,7 +59,7 @@ LL | fn return_dyn_incompatible_rc() -> std::rc::Rc<dyn DynIncompatible4> {
    |                                                ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible4` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:15:22
    |
 LL | trait DynIncompatible4 {
@@ -75,7 +75,7 @@ LL | impl Trait for dyn DynIncompatible1 {}
    |                ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25
    |
 LL | trait DynIncompatible1: Sized {}
diff --git a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs
deleted file mode 100644
index 71caf43806d..00000000000
--- a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#![crate_type = "lib"]
-
-// This isn't intended to compile, so it's easiest to just ignore this error.
-extern crate rustc_serialize; //~ERROR can't find crate for `rustc_serialize`
-
-#[derive(
-    RustcEncodable,
-    //~^   ERROR   use of unstable library feature `rustc_encodable_decodable`
-    //~^^  WARNING this was previously accepted by the compiler
-    //~^^^ WARNING use of deprecated macro `RustcEncodable`
-    RustcDecodable,
-    //~^   ERROR   use of unstable library feature `rustc_encodable_decodable`
-    //~^^  WARNING this was previously accepted by the compiler
-    //~^^^ WARNING use of deprecated macro `RustcDecodable`
-)]
-struct S;
diff --git a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr
deleted file mode 100644
index b949dbb9da2..00000000000
--- a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr
+++ /dev/null
@@ -1,66 +0,0 @@
-error[E0463]: can't find crate for `rustc_serialize`
-  --> $DIR/feature-gate-rustc_encodable_decodable.rs:4:1
-   |
-LL | extern crate rustc_serialize;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
-   |
-   = help: maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
-
-error: use of unstable library feature `rustc_encodable_decodable`: derive macro for `rustc-serialize`; should not be used in new code
-  --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5
-   |
-LL |     RustcEncodable,
-   |     ^^^^^^^^^^^^^^
-   |
-   = 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>
-   = note: `#[deny(soft_unstable)]` on by default
-
-warning: use of deprecated macro `RustcEncodable`: rustc-serialize is deprecated and no longer supported
-  --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5
-   |
-LL |     RustcEncodable,
-   |     ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(deprecated)]` on by default
-
-error: use of unstable library feature `rustc_encodable_decodable`: derive macro for `rustc-serialize`; should not be used in new code
-  --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5
-   |
-LL |     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>
-
-warning: use of deprecated macro `RustcDecodable`: rustc-serialize is deprecated and no longer supported
-  --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5
-   |
-LL |     RustcDecodable,
-   |     ^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors; 2 warnings emitted
-
-For more information about this error, try `rustc --explain E0463`.
-Future incompatibility report: Future breakage diagnostic:
-error: use of unstable library feature `rustc_encodable_decodable`: derive macro for `rustc-serialize`; should not be used in new code
-  --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5
-   |
-LL |     RustcEncodable,
-   |     ^^^^^^^^^^^^^^
-   |
-   = 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>
-   = note: `#[deny(soft_unstable)]` on by default
-
-Future breakage diagnostic:
-error: use of unstable library feature `rustc_encodable_decodable`: derive macro for `rustc-serialize`; should not be used in new code
-  --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5
-   |
-LL |     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>
-   = note: `#[deny(soft_unstable)]` on by default
-
diff --git a/tests/ui/fn/fn-pointer-mismatch.stderr b/tests/ui/fn/fn-pointer-mismatch.stderr
index 9cda11639d0..2aa840911f6 100644
--- a/tests/ui/fn/fn-pointer-mismatch.stderr
+++ b/tests/ui/fn/fn-pointer-mismatch.stderr
@@ -67,7 +67,7 @@ LL |     let d: &fn(u32) -> u32 = foo;
 help: consider using a reference
    |
 LL |     let d: &fn(u32) -> u32 = &foo;
-   |                              ~~~~
+   |                              +
 
 error[E0308]: mismatched types
   --> $DIR/fn-pointer-mismatch.rs:48:30
diff --git a/tests/ui/force-inlining/cast.stderr b/tests/ui/force-inlining/cast.stderr
index 116919e5fe7..53132959659 100644
--- a/tests/ui/force-inlining/cast.stderr
+++ b/tests/ui/force-inlining/cast.stderr
@@ -12,7 +12,7 @@ LL |     let _: fn(isize) -> usize = callee;
 help: consider casting to a fn pointer
    |
 LL |     let _: fn(isize) -> usize = callee as fn(isize) -> usize;
-   |                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |                                        +++++++++++++++++++++
 
 error[E0605]: non-primitive cast: `fn(isize) -> usize {callee}` as `fn(isize) -> usize`
   --> $DIR/cast.rs:15:13
@@ -32,7 +32,7 @@ LL |         callee,
 help: consider casting to a fn pointer
    |
 LL |         callee as fn(isize) -> usize,
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |                +++++++++++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
index 4c5a47e73c6..c9b46de5c33 100644
--- a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
+++ b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
@@ -43,7 +43,7 @@ LL |   fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:2:8
    |
 LL | trait X {
diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.stderr
index df79556c825..e57f6b48401 100644
--- a/tests/ui/generic-associated-types/gat-in-trait-path.stderr
+++ b/tests/ui/generic-associated-types/gat-in-trait-path.stderr
@@ -5,7 +5,7 @@ LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/gat-in-trait-path.rs:6:10
    |
 LL | trait Foo {
@@ -21,7 +21,7 @@ LL |   f(Box::new(foo));
    |     ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/gat-in-trait-path.rs:6:10
    |
 LL | trait Foo {
@@ -37,7 +37,7 @@ LL |   f(Box::new(foo));
    |     ^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/gat-in-trait-path.rs:6:10
    |
 LL | trait Foo {
diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
index 499ce8e4a32..52fed354edf 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
+++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
@@ -130,7 +130,7 @@ LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
    |                     ^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/gat-trait-path-parenthesised-args.rs:2:8
    |
 LL | trait X {
@@ -196,7 +196,7 @@ LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
    |                     ^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/gat-trait-path-parenthesised-args.rs:2:8
    |
 LL | trait X {
diff --git a/tests/ui/generic-associated-types/issue-67510-pass.stderr b/tests/ui/generic-associated-types/issue-67510-pass.stderr
index f6846f833fe..4b56c4ef35f 100644
--- a/tests/ui/generic-associated-types/issue-67510-pass.stderr
+++ b/tests/ui/generic-associated-types/issue-67510-pass.stderr
@@ -5,7 +5,7 @@ LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {}
    |                       ^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-67510-pass.rs:4:10
    |
 LL | trait X {
diff --git a/tests/ui/generic-associated-types/issue-67510.stderr b/tests/ui/generic-associated-types/issue-67510.stderr
index e8555a7aa1f..f5c494788ea 100644
--- a/tests/ui/generic-associated-types/issue-67510.stderr
+++ b/tests/ui/generic-associated-types/issue-67510.stderr
@@ -36,7 +36,7 @@ LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
    |             ^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-67510.rs:2:10
    |
 LL | trait X {
diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr
index a78151384d4..56439f6dfea 100644
--- a/tests/ui/generic-associated-types/issue-71176.stderr
+++ b/tests/ui/generic-associated-types/issue-71176.stderr
@@ -55,7 +55,7 @@ LL |   inner: Box<dyn Provider<A = B>>,
    |              ^^^^^^^^^^^^^^^^^^^ `Provider` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-71176.rs:2:10
    |
 LL | trait Provider {
@@ -72,7 +72,7 @@ LL |         inner: Box::new(()),
    |                ^^^^^^^^^^^^ `Provider` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-71176.rs:2:10
    |
 LL | trait Provider {
@@ -89,7 +89,7 @@ LL |         inner: Box::new(()),
    |                ^^^^^^^^^^^^ `Provider` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-71176.rs:2:10
    |
 LL | trait Provider {
diff --git a/tests/ui/generic-associated-types/issue-76535.stderr b/tests/ui/generic-associated-types/issue-76535.stderr
index 6b7c3bfe731..b828234afa1 100644
--- a/tests/ui/generic-associated-types/issue-76535.stderr
+++ b/tests/ui/generic-associated-types/issue-76535.stderr
@@ -21,7 +21,7 @@ LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruc
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-76535.rs:4:10
    |
 LL | pub trait SuperTrait {
@@ -39,7 +39,7 @@ LL |     let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruc
    |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-76535.rs:4:10
    |
 LL | pub trait SuperTrait {
diff --git a/tests/ui/generic-associated-types/issue-78671.stderr b/tests/ui/generic-associated-types/issue-78671.stderr
index c85e97067cb..c6da137672d 100644
--- a/tests/ui/generic-associated-types/issue-78671.stderr
+++ b/tests/ui/generic-associated-types/issue-78671.stderr
@@ -21,7 +21,7 @@ LL |     Box::new(Family) as &dyn CollectionFamily<Member=usize>
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-78671.rs:2:10
    |
 LL | trait CollectionFamily {
diff --git a/tests/ui/generic-associated-types/issue-79422.stderr b/tests/ui/generic-associated-types/issue-79422.stderr
index a81217e96c3..6311e4de272 100644
--- a/tests/ui/generic-associated-types/issue-79422.stderr
+++ b/tests/ui/generic-associated-types/issue-79422.stderr
@@ -21,7 +21,7 @@ LL |         as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-79422.rs:18:10
    |
 LL | trait MapLike<K, V> {
@@ -37,7 +37,7 @@ LL |     let m = Box::new(std::collections::BTreeMap::<u8, u8>::new())
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-79422.rs:18:10
    |
 LL | trait MapLike<K, V> {
diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.rs b/tests/ui/generic-associated-types/issue-90014-tait2.rs
index ef54a89aaae..3f7a9ff63c3 100644
--- a/tests/ui/generic-associated-types/issue-90014-tait2.rs
+++ b/tests/ui/generic-associated-types/issue-90014-tait2.rs
@@ -3,8 +3,6 @@
 //! Unfortunately we don't even reach opaque type collection, as we ICE in typeck before that.
 //! See #109281 for the original report.
 //@ edition:2018
-//@ error-pattern: expected generic lifetime parameter, found `'a`
-
 #![feature(type_alias_impl_trait)]
 
 use std::future::Future;
@@ -24,6 +22,7 @@ impl<'x, T: 'x> Trait<'x> for (T,) {
 impl Foo<'_> {
     fn make_fut(&self) -> Box<dyn for<'a> Trait<'a, Thing = Fut<'a>>> {
         Box::new((async { () },))
+        //~^ ERROR expected generic lifetime parameter, found `'a`
     }
 }
 
diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.stderr b/tests/ui/generic-associated-types/issue-90014-tait2.stderr
index be6f4272ce1..aa427d42649 100644
--- a/tests/ui/generic-associated-types/issue-90014-tait2.stderr
+++ b/tests/ui/generic-associated-types/issue-90014-tait2.stderr
@@ -1,5 +1,5 @@
 error[E0792]: expected generic lifetime parameter, found `'a`
-  --> $DIR/issue-90014-tait2.rs:26:9
+  --> $DIR/issue-90014-tait2.rs:24:9
    |
 LL | type Fut<'a> = impl Future<Output = ()>;
    |          -- this generic parameter must be used with a generic lifetime parameter
diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.stderr b/tests/ui/generic-associated-types/missing_lifetime_args.stderr
index 6b8df5cc12f..7b6888817f4 100644
--- a/tests/ui/generic-associated-types/missing_lifetime_args.stderr
+++ b/tests/ui/generic-associated-types/missing_lifetime_args.stderr
@@ -55,7 +55,7 @@ LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y = (&'c u32, &'d u32)>>) {}
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/missing_lifetime_args.rs:2:10
    |
 LL | trait X {
diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
index 5c9e9dbe3d7..45bca1a7628 100644
--- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
+++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
@@ -99,7 +99,7 @@ LL |   fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
    |                       ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/trait-path-type-error-once-implemented.rs:2:10
    |
 LL | trait X {
diff --git a/tests/ui/generic-associated-types/trait-objects.stderr b/tests/ui/generic-associated-types/trait-objects.stderr
index 56a1cb1906f..7d95718ec87 100644
--- a/tests/ui/generic-associated-types/trait-objects.stderr
+++ b/tests/ui/generic-associated-types/trait-objects.stderr
@@ -5,7 +5,7 @@ LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> u
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/trait-objects.rs:2:10
    |
 LL | trait StreamingIterator {
@@ -21,7 +21,7 @@ LL |     x.size_hint().0
    |       ^^^^^^^^^ `StreamingIterator` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/trait-objects.rs:2:10
    |
 LL | trait StreamingIterator {
@@ -37,7 +37,7 @@ LL |     x.size_hint().0
    |     ^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/trait-objects.rs:2:10
    |
 LL | trait StreamingIterator {
diff --git a/tests/ui/generic-const-items/def-site-eval.fail.stderr b/tests/ui/generic-const-items/def-site-eval.fail.stderr
new file mode 100644
index 00000000000..22a5f291697
--- /dev/null
+++ b/tests/ui/generic-const-items/def-site-eval.fail.stderr
@@ -0,0 +1,11 @@
+error[E0080]: evaluation of `_::<'_>` failed
+  --> $DIR/def-site-eval.rs:14:20
+   |
+LL | const _<'_a>: () = panic!();
+   |                    ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/def-site-eval.rs:14:20
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/generic-const-items/def-site-eval.rs b/tests/ui/generic-const-items/def-site-eval.rs
new file mode 100644
index 00000000000..3ed7f96aed0
--- /dev/null
+++ b/tests/ui/generic-const-items/def-site-eval.rs
@@ -0,0 +1,16 @@
+//! Test that we only evaluate free const items (their def site to be clear)
+//! whose generics don't require monomorphization.
+#![feature(generic_const_items)]
+#![allow(incomplete_features)]
+
+//@ revisions: fail pass
+//@[fail] build-fail (we require monomorphization)
+//@[pass] build-pass (we require monomorphization)
+
+const _<_T>: () = panic!();
+const _<const _N: usize>: () = panic!();
+
+#[cfg(fail)]
+const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation of `_::<'_>` failed
+
+fn main() {}
diff --git a/tests/ui/generic-const-items/def-site-mono.rs b/tests/ui/generic-const-items/def-site-mono.rs
new file mode 100644
index 00000000000..f10d450f6bd
--- /dev/null
+++ b/tests/ui/generic-const-items/def-site-mono.rs
@@ -0,0 +1,13 @@
+//! Ensure that we don't try to collect monomorphizeable items inside free const
+//! items (their def site to be clear) whose generics require monomorphization.
+//!
+//! Such items are to be collected at instantiation sites of free consts.
+
+#![feature(generic_const_items)]
+#![allow(incomplete_features)]
+
+//@ build-pass (we require monomorphization)
+
+const _IDENTITY<T>: fn(T) -> T = |x| x;
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr
index 67417a5e525..be2eca3e61a 100644
--- a/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr
@@ -11,7 +11,7 @@ LL | |     ),
 LL | | ) {
    | |_- expected `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))` because of return type
 LL |       f
-   |       ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&...)))`, found `&dyn Fn(u32)`
+   |       ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&...))))`, found `&dyn Fn(u32)`
    |
    = note: expected reference `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))`
               found reference `&dyn Fn(u32)`
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs
index e70f6fc3430..c8963e078f0 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs
+++ b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs
@@ -36,12 +36,10 @@ trait Ty<'a> {
 
 fn main() {
     let v = Unit2.m(
-        L {
-            //~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
-            //~| ERROR type mismatch
+        L { //~ ERROR type mismatch
             f: |x| {
                 drop(x);
-                Unit4
+                Unit4 //~ ERROR to return `Unit3`, but it returns `Unit4`
             },
         },
     );
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr
index 74610b55dc3..4302570cdbd 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr
@@ -1,16 +1,15 @@
-error[E0271]: type mismatch resolving `<L<{closure@issue-62203-hrtb-ice.rs:42:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V`
+error[E0271]: type mismatch resolving `<L<{closure@issue-62203-hrtb-ice.rs:40:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V`
   --> $DIR/issue-62203-hrtb-ice.rs:39:9
    |
 LL |       let v = Unit2.m(
    |                     - required by a bound introduced by this call
 LL | /         L {
-LL | |
-LL | |
 LL | |             f: |x| {
-...  |
+LL | |                 drop(x);
+LL | |                 Unit4
 LL | |             },
 LL | |         },
-   | |_________^ type mismatch resolving `<L<{closure@issue-62203-hrtb-ice.rs:42:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V`
+   | |_________^ type mismatch resolving `<L<{closure@issue-62203-hrtb-ice.rs:40:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V`
    |
 note: expected this to be `<_ as Ty<'_>>::V`
   --> $DIR/issue-62203-hrtb-ice.rs:21:14
@@ -30,21 +29,19 @@ LL |     where
 LL |         F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
    |                                                   ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
 
-error[E0271]: expected `{closure@issue-62203-hrtb-ice.rs:42:16}` to be a closure that returns `Unit3`, but it returns `Unit4`
-  --> $DIR/issue-62203-hrtb-ice.rs:39:9
-   |
-LL |       let v = Unit2.m(
-   |                     - required by a bound introduced by this call
-LL | /         L {
-LL | |
-LL | |
-LL | |             f: |x| {
-...  |
-LL | |             },
-LL | |         },
-   | |_________^ expected `Unit3`, found `Unit4`
-   |
-note: required for `L<{closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19}>` to implement `for<'r> T0<'r, (&'r u8,)>`
+error[E0271]: expected `{closure@issue-62203-hrtb-ice.rs:40:16}` to return `Unit3`, but it returns `Unit4`
+  --> $DIR/issue-62203-hrtb-ice.rs:42:17
+   |
+LL |     let v = Unit2.m(
+   |                   - required by a bound introduced by this call
+LL |         L {
+LL |             f: |x| {
+   |                --- this closure
+LL |                 drop(x);
+LL |                 Unit4
+   |                 ^^^^^ expected `Unit3`, found `Unit4`
+   |
+note: required for `L<{closure@$DIR/issue-62203-hrtb-ice.rs:40:16: 40:19}>` to implement `for<'r> T0<'r, (&'r u8,)>`
   --> $DIR/issue-62203-hrtb-ice.rs:17:16
    |
 LL | impl<'a, A, T> T0<'a, A> for L<T>
diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr
index fc3d9c2171d..183ee678d7a 100644
--- a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr
@@ -5,7 +5,7 @@ LL |     let x: &dyn Foo = &();
    |                       ^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/span-bug-issue-121597.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
@@ -21,7 +21,7 @@ LL |     let x: &dyn Foo = &();
    |            ^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/span-bug-issue-121597.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
diff --git a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr
index 4abd7bcf31c..2869702d7fc 100644
--- a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr
+++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr
@@ -5,7 +5,7 @@ LL | fn car() -> dyn DynIncompatible {
    |             ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8
    |
 LL | trait DynIncompatible {
@@ -33,7 +33,7 @@ LL | fn cat() -> Box<dyn DynIncompatible> {
    |                 ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8
    |
 LL | trait DynIncompatible {
@@ -78,7 +78,7 @@ LL |         return Box::new(A);
    |                ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8
    |
 LL | trait DynIncompatible {
@@ -107,7 +107,7 @@ LL |     Box::new(B)
    |     ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8
    |
 LL | trait DynIncompatible {
diff --git a/tests/ui/impl-trait/impl-trait-in-macro.stderr b/tests/ui/impl-trait/impl-trait-in-macro.stderr
index 4380f47c5de..2f934694f83 100644
--- a/tests/ui/impl-trait/impl-trait-in-macro.stderr
+++ b/tests/ui/impl-trait/impl-trait-in-macro.stderr
@@ -12,8 +12,8 @@ LL |     let mut a = x;
 LL |     a = y;
    |         ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
    |
-   = note: expected type parameter `impl Debug` (type parameter `impl Debug`)
-              found type parameter `impl Debug` (type parameter `impl Debug`)
+   = note: expected type parameter `impl Debug`
+              found type parameter `impl Debug`
    = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
index 1cfc2a6d944..a95670ced86 100644
--- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
+++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
@@ -18,6 +18,11 @@ help: this trait has no implementations, consider adding one
    |
 LL | trait Foo {}
    | ^^^^^^^^^
+note: required by a bound in `A`
+  --> $DIR/alias-bounds-when-not-wf.rs:8:11
+   |
+LL | type A<T: Foo> = T;
+   |           ^^^ required by this bound in `A`
 
 error[E0277]: the trait bound `usize: Foo` is not satisfied
   --> $DIR/alias-bounds-when-not-wf.rs:16:10
diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr
index 44ca09150fe..61fe9432a1e 100644
--- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr
+++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr
@@ -15,7 +15,7 @@ LL |         MyTrait::foo(&self)
    |         ^^^^^^^^^^^^ `MyTrait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22
    |
 LL | trait MyTrait {
@@ -40,7 +40,7 @@ LL | impl dyn MyTrait {
    |      ^^^^^^^^^^^ `MyTrait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22
    |
 LL | trait MyTrait {
@@ -57,7 +57,7 @@ LL |     fn other(&self) -> impl Marker {
    |               ^^^^ `MyTrait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22
    |
 LL | trait MyTrait {
diff --git a/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.rs b/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.rs
new file mode 100644
index 00000000000..fe73306966e
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.rs
@@ -0,0 +1,14 @@
+// There's a suggestion that turns `Iterator<u32>` into `Iterator<Item = u32>`
+// if we have more generics than the trait wants. Let's not consider RPITITs
+// for this, since that makes no sense right now.
+
+trait Foo {
+    fn bar(self) -> impl Sized;
+}
+
+impl Foo<u8> for () {
+    //~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
+    fn bar(self) -> impl Sized {}
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.stderr b/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.stderr
new file mode 100644
index 00000000000..fb497b89c5f
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.stderr
@@ -0,0 +1,17 @@
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/dont-consider-unconstrained-rpitits.rs:9:6
+   |
+LL | impl Foo<u8> for () {
+   |      ^^^---- help: remove the unnecessary generics
+   |      |
+   |      expected 0 generic arguments
+   |
+note: trait defined here, with 0 generic parameters
+  --> $DIR/dont-consider-unconstrained-rpitits.rs:5:7
+   |
+LL | trait Foo {
+   |       ^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr
index 87a5480b1e3..840c27e183f 100644
--- a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr
+++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr
@@ -5,7 +5,7 @@ LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
    |                                 ^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-compatibility.rs:4:22
    |
 LL | trait Foo {
@@ -22,7 +22,7 @@ LL |     let s = i.baz();
    |               ^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-compatibility.rs:4:22
    |
 LL | trait Foo {
@@ -39,7 +39,7 @@ LL |     let s = i.baz();
    |             ^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-compatibility.rs:4:22
    |
 LL | trait Foo {
@@ -56,7 +56,7 @@ LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
    |             ^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-compatibility.rs:4:22
    |
 LL | trait Foo {
diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr
index 07d09468b04..29235ca78a5 100644
--- a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr
+++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr
@@ -5,7 +5,7 @@ LL |     let _: &dyn rpitit::Foo = todo!();
    |            ^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/auxiliary/rpitit.rs:4:21
    |
 LL |     fn bar(self) -> impl Deref<Target = impl Sized>;
diff --git a/tests/ui/impl-trait/universal-two-impl-traits.stderr b/tests/ui/impl-trait/universal-two-impl-traits.stderr
index 3b4844ab133..f2f5dd0a0c8 100644
--- a/tests/ui/impl-trait/universal-two-impl-traits.stderr
+++ b/tests/ui/impl-trait/universal-two-impl-traits.stderr
@@ -10,8 +10,8 @@ LL |     let mut a = x;
 LL |     a = y;
    |         ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
    |
-   = note: expected type parameter `impl Debug` (type parameter `impl Debug`)
-              found type parameter `impl Debug` (type parameter `impl Debug`)
+   = note: expected type parameter `impl Debug`
+              found type parameter `impl Debug`
    = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
diff --git a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs
index e28b8f373da..62fc079d9d9 100644
--- a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs
+++ b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs
@@ -3,6 +3,9 @@
 //@ error-pattern: reached the recursion limit while instantiating
 //@ error-pattern: reached the recursion limit finding the struct tail
 
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'"
+
 // Regression test for #114484: This used to ICE during monomorphization, because we treated
 // `<VirtualWrapper<...> as Pointee>::Metadata` as a rigid projection after reaching the recursion
 // limit when finding the struct tail.
diff --git a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.stderr b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.stderr
index 7c961b79c0c..b67e000bf74 100644
--- a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.stderr
+++ b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.stderr
@@ -18,7 +18,7 @@ error: reached the recursion limit finding the struct tail for `[u8; 256]`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<SomeData<256>, 0>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>>`
-  --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:26:18
+  --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:29:18
    |
 LL |         unsafe { virtualize_my_trait(L, self) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +43,7 @@ error: reached the recursion limit finding the struct tail for `SomeData<256>`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<SomeData<256>, 0>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>>`
-  --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:26:18
+  --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:29:18
    |
 LL |         unsafe { virtualize_my_trait(L, self) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ error: reached the recursion limit finding the struct tail for `VirtualWrapper<S
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<SomeData<256>, 0>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>>`
-  --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:26:18
+  --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:29:18
    |
 LL |         unsafe { virtualize_my_trait(L, self) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -76,11 +76,11 @@ LL |         unsafe { virtualize_my_trait(L, self) }
 error: reached the recursion limit while instantiating `<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<..., 1>, 1>, 1>, 1>, 1> as MyTrait>::virtualize`
    |
 note: `<VirtualWrapper<T, L> as MyTrait>::virtualize` defined here
-  --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:25:5
+  --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:28:5
    |
 LL |     fn virtualize(&self) -> &dyn MyTrait {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the full type name has been written to '$TEST_BUILD_DIR/infinite/infinite-instantiation-struct-tail-ice-114484/infinite-instantiation-struct-tail-ice-114484.long-type.txt'
+   = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt'
 
 error: aborting due to 13 previous errors
 
diff --git a/tests/ui/infinite/infinite-instantiation.rs b/tests/ui/infinite/infinite-instantiation.rs
index 7e1bff6b124..d5cb8e79592 100644
--- a/tests/ui/infinite/infinite-instantiation.rs
+++ b/tests/ui/infinite/infinite-instantiation.rs
@@ -1,5 +1,6 @@
 //@ build-fail
-//@ normalize-stderr: ".nll/" -> "/"
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'"
 
 trait ToOpt: Sized {
     fn to_option(&self) -> Option<Self>;
diff --git a/tests/ui/infinite/infinite-instantiation.stderr b/tests/ui/infinite/infinite-instantiation.stderr
index 43d267fa46b..71c745cf5eb 100644
--- a/tests/ui/infinite/infinite-instantiation.stderr
+++ b/tests/ui/infinite/infinite-instantiation.stderr
@@ -1,15 +1,15 @@
 error: reached the recursion limit while instantiating `function::<Option<Option<Option<Option<Option<...>>>>>>`
-  --> $DIR/infinite-instantiation.rs:22:9
+  --> $DIR/infinite-instantiation.rs:23:9
    |
 LL |         function(counter - 1, t.to_option());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `function` defined here
-  --> $DIR/infinite-instantiation.rs:20:1
+  --> $DIR/infinite-instantiation.rs:21:1
    |
 LL | fn function<T:ToOpt + Clone>(counter: usize, t: T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the full type name has been written to '$TEST_BUILD_DIR/infinite/infinite-instantiation/infinite-instantiation.long-type.txt'
+   = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt'
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/intrinsics/const-eval-select-bad.rs b/tests/ui/intrinsics/const-eval-select-bad.rs
index 7e75de88d29..3365d57af7c 100644
--- a/tests/ui/intrinsics/const-eval-select-bad.rs
+++ b/tests/ui/intrinsics/const-eval-select-bad.rs
@@ -30,7 +30,7 @@ fn baz(n: bool) -> i32 {
 
 const fn return_ty_mismatch() {
     const_eval_select((1,), foo, bar);
-    //~^ ERROR expected `bar` to be a fn item that returns `i32`, but it returns `bool`
+    //~^ ERROR expected `bar` to return `i32`, but it returns `bool`
 }
 
 const fn args_ty_mismatch() {
diff --git a/tests/ui/intrinsics/const-eval-select-bad.stderr b/tests/ui/intrinsics/const-eval-select-bad.stderr
index e317ed23ab1..bb159bed282 100644
--- a/tests/ui/intrinsics/const-eval-select-bad.stderr
+++ b/tests/ui/intrinsics/const-eval-select-bad.stderr
@@ -60,7 +60,7 @@ LL |     const_eval_select((), 42, 0xDEADBEEF);
    = note: expected a function item, found {integer}
    = help: consult the documentation on `const_eval_select` for more information
 
-error[E0271]: expected `bar` to be a fn item that returns `i32`, but it returns `bool`
+error[E0271]: expected `bar` to return `i32`, but it returns `bool`
   --> $DIR/const-eval-select-bad.rs:32:34
    |
 LL |     const_eval_select((1,), foo, bar);
diff --git a/tests/ui/issues/issue-18959.stderr b/tests/ui/issues/issue-18959.stderr
index 49d501c397f..c37c4177bfc 100644
--- a/tests/ui/issues/issue-18959.stderr
+++ b/tests/ui/issues/issue-18959.stderr
@@ -5,7 +5,7 @@ LL | fn foo(b: &dyn Bar) {
    |            ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
@@ -21,7 +21,7 @@ LL |     b.foo(&0)
    |     ^^^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
@@ -37,7 +37,7 @@ LL |     let test: &dyn Bar = &mut thing;
    |               ^^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
@@ -53,7 +53,7 @@ LL |     let test: &dyn Bar = &mut thing;
    |                          ^^^^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
@@ -70,7 +70,7 @@ LL |     foo(test);
    |         ^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-18959.rs:1:20
    |
 LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
diff --git a/tests/ui/issues/issue-19380.stderr b/tests/ui/issues/issue-19380.stderr
index 7d4812c3693..f8509891d3a 100644
--- a/tests/ui/issues/issue-19380.stderr
+++ b/tests/ui/issues/issue-19380.stderr
@@ -5,7 +5,7 @@ LL |   foos: &'static [&'static (dyn Qiz + 'static)]
    |                             ^^^^^^^^^^^^^^^^^ `Qiz` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-19380.rs:2:6
    |
 LL | trait Qiz {
@@ -29,7 +29,7 @@ LL | const BAR : Bar = Bar { foos: &[&FOO]};
    |                                 ^^^^ `Qiz` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-19380.rs:2:6
    |
 LL | trait Qiz {
@@ -54,7 +54,7 @@ LL | const BAR : Bar = Bar { foos: &[&FOO]};
    |                               ^^^^^^^ `Qiz` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-19380.rs:2:6
    |
 LL | trait Qiz {
diff --git a/tests/ui/issues/issue-26056.stderr b/tests/ui/issues/issue-26056.stderr
index d1cdf43351e..c2168af9496 100644
--- a/tests/ui/issues/issue-26056.stderr
+++ b/tests/ui/issues/issue-26056.stderr
@@ -5,7 +5,7 @@ LL |         as &dyn Map<Key=u32,MapValue=u32>;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ `Map` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-26056.rs:9:12
    |
 LL | trait Map: MapLookup<<Self as Map>::Key> {
diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs
index edf4f2fce26..ebaf244ac9c 100644
--- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs
+++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs
@@ -1,5 +1,6 @@
 //@ build-fail
-//@ normalize-stderr: ".nll/" -> "/"
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'"
 
 trait Mirror {
     type Image;
diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
index 84ed97572b3..fbbf80021be 100644
--- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
+++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr
@@ -1,15 +1,15 @@
 error: reached the recursion limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse`
-  --> $DIR/issue-37311.rs:17:9
+  --> $DIR/issue-37311.rs:18:9
    |
 LL |         (self, self).recurse();
    |         ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `<T as Foo>::recurse` defined here
-  --> $DIR/issue-37311.rs:16:5
+  --> $DIR/issue-37311.rs:17:5
    |
 LL |     fn recurse(&self) {
    |     ^^^^^^^^^^^^^^^^^
-   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt'
+   = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt'
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-50781.stderr b/tests/ui/issues/issue-50781.stderr
index 293e9839944..88b83a83e0c 100644
--- a/tests/ui/issues/issue-50781.stderr
+++ b/tests/ui/issues/issue-50781.stderr
@@ -5,7 +5,7 @@ LL | impl Trait for dyn X {}
    |                ^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-50781.rs:4:8
    |
 LL | trait X {
@@ -22,7 +22,7 @@ LL |     <dyn X as X>::foo(&());
    |                       ^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-50781.rs:4:8
    |
 LL | trait X {
@@ -40,7 +40,7 @@ LL |     <dyn X as X>::foo(&());
    |      ^^^^^ `X` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-50781.rs:4:8
    |
 LL | trait X {
diff --git a/tests/ui/issues/issue-67552.rs b/tests/ui/issues/issue-67552.rs
index 343ae4f262f..8c7e95bd2e3 100644
--- a/tests/ui/issues/issue-67552.rs
+++ b/tests/ui/issues/issue-67552.rs
@@ -1,6 +1,7 @@
 //@ build-fail
 //@ compile-flags: -Copt-level=0
-//@ normalize-stderr: ".nll/" -> "/"
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'"
 
 fn main() {
     rec(Empty);
diff --git a/tests/ui/issues/issue-67552.stderr b/tests/ui/issues/issue-67552.stderr
index 1a8d7248b45..f94cd78c870 100644
--- a/tests/ui/issues/issue-67552.stderr
+++ b/tests/ui/issues/issue-67552.stderr
@@ -1,17 +1,17 @@
 error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut ...>`
-  --> $DIR/issue-67552.rs:29:9
+  --> $DIR/issue-67552.rs:30:9
    |
 LL |         rec(identity(&mut it))
    |         ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `rec` defined here
-  --> $DIR/issue-67552.rs:22:1
+  --> $DIR/issue-67552.rs:23:1
    |
 LL | / fn rec<T>(mut it: T)
 LL | | where
 LL | |     T: Iterator,
    | |________________^
-   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-67552/issue-67552.long-type.txt'
+   = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt'
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-8727.rs b/tests/ui/issues/issue-8727.rs
index b824be7c12f..7767729109e 100644
--- a/tests/ui/issues/issue-8727.rs
+++ b/tests/ui/issues/issue-8727.rs
@@ -2,7 +2,8 @@
 // recursions.
 
 //@ build-fail
-//@ normalize-stderr: ".nll/" -> "/"
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'"
 
 fn generic<T>() { //~ WARN function cannot return without recursing
     generic::<Option<T>>();
diff --git a/tests/ui/issues/issue-8727.stderr b/tests/ui/issues/issue-8727.stderr
index 9af598fe43f..22286eb8d7b 100644
--- a/tests/ui/issues/issue-8727.stderr
+++ b/tests/ui/issues/issue-8727.stderr
@@ -1,5 +1,5 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-8727.rs:7:1
+  --> $DIR/issue-8727.rs:8:1
    |
 LL | fn generic<T>() {
    | ^^^^^^^^^^^^^^^ cannot return without recursing
@@ -10,17 +10,17 @@ LL |     generic::<Option<T>>();
    = note: `#[warn(unconditional_recursion)]` on by default
 
 error: reached the recursion limit while instantiating `generic::<Option<Option<Option<Option<Option<...>>>>>>`
-  --> $DIR/issue-8727.rs:8:5
+  --> $DIR/issue-8727.rs:9:5
    |
 LL |     generic::<Option<T>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `generic` defined here
-  --> $DIR/issue-8727.rs:7:1
+  --> $DIR/issue-8727.rs:8:1
    |
 LL | fn generic<T>() {
    | ^^^^^^^^^^^^^^^
-   = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-8727/issue-8727.long-type.txt'
+   = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt'
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
index 83446fc9ec0..95048c4454b 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
@@ -26,7 +26,7 @@ LL |     let z = &x as &dyn Foo;
    |                   ^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/kindck-inherited-copy-bound.rs:10:13
    |
 LL | trait Foo : Copy {
@@ -41,7 +41,7 @@ LL |     let z = &x as &dyn Foo;
    |             ^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/kindck-inherited-copy-bound.rs:10:13
    |
 LL | trait Foo : Copy {
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
index 271e5afb9e7..296f011193e 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
@@ -26,7 +26,7 @@ LL |     let z = &x as &dyn Foo;
    |             ^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/kindck-inherited-copy-bound.rs:10:13
    |
 LL | trait Foo : Copy {
diff --git a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs
new file mode 100644
index 00000000000..90bb0a294f8
--- /dev/null
+++ b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs
@@ -0,0 +1,9 @@
+//! Ensure that we check generic parameter defaults for well-formedness at the definition site.
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Alias<T = Vec<str>, const N: usize = {0 - 1}> = T;
+//~^ ERROR evaluation of constant value failed
+//~| ERROR the size for values of type `str` cannot be known at compilation time
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr
new file mode 100644
index 00000000000..da0021ccaf4
--- /dev/null
+++ b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/def-site-param-defaults-wf.rs:5:44
+   |
+LL | type Alias<T = Vec<str>, const N: usize = {0 - 1}> = T;
+   |                                            ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/def-site-param-defaults-wf.rs:5:16
+   |
+LL | type Alias<T = Vec<str>, const N: usize = {0 - 1}> = T;
+   |                ^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+note: required by an implicit `Sized` bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0080, E0277.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/lazy-type-alias/def-site-predicates-wf.rs b/tests/ui/lazy-type-alias/def-site-predicates-wf.rs
new file mode 100644
index 00000000000..5d9235347cb
--- /dev/null
+++ b/tests/ui/lazy-type-alias/def-site-predicates-wf.rs
@@ -0,0 +1,13 @@
+//! Ensure that we check the predicates at the definition site for well-formedness.
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Alias0 = ()
+where
+    Vec<str>:; //~ ERROR the size for values of type `str` cannot be known at compilation time
+
+type Alias1 = ()
+where
+    Vec<str>: Sized; //~ ERROR the size for values of type `str` cannot be known at compilation time
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/def-site-predicates-wf.stderr b/tests/ui/lazy-type-alias/def-site-predicates-wf.stderr
new file mode 100644
index 00000000000..b44e702c35c
--- /dev/null
+++ b/tests/ui/lazy-type-alias/def-site-predicates-wf.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/def-site-predicates-wf.rs:7:5
+   |
+LL |     Vec<str>:;
+   |     ^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+note: required by an implicit `Sized` bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/def-site-predicates-wf.rs:11:15
+   |
+LL |     Vec<str>: Sized;
+   |               ^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+note: required by an implicit `Sized` bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.rs b/tests/ui/lint/dead-code/lint-dead-code-1.rs
index ddcafedf7bc..a7f654b5d8b 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-1.rs
+++ b/tests/ui/lint/dead-code/lint-dead-code-1.rs
@@ -29,6 +29,7 @@ const used_const: isize = 0;
 pub const used_const2: isize = used_const;
 const USED_CONST: isize = 1;
 const CONST_USED_IN_ENUM_DISCRIMINANT: isize = 11;
+const CONST_USED_IN_RANGE_PATTERN: isize = 12;
 
 pub type typ = *const UsedStruct4;
 pub struct PubStruct;
@@ -81,6 +82,7 @@ pub fn pub_fn() {
     match i {
         USED_STATIC => (),
         USED_CONST => (),
+        CONST_USED_IN_RANGE_PATTERN..100 => {}
         _ => ()
     }
     f::<StructUsedInGeneric>();
diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.stderr b/tests/ui/lint/dead-code/lint-dead-code-1.stderr
index eb728b5b930..c4410114cea 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-1.stderr
+++ b/tests/ui/lint/dead-code/lint-dead-code-1.stderr
@@ -17,19 +17,19 @@ LL | const priv_const: isize = 0;
    |       ^^^^^^^^^^
 
 error: struct `PrivStruct` is never constructed
-  --> $DIR/lint-dead-code-1.rs:35:8
+  --> $DIR/lint-dead-code-1.rs:36:8
    |
 LL | struct PrivStruct;
    |        ^^^^^^^^^^
 
 error: enum `priv_enum` is never used
-  --> $DIR/lint-dead-code-1.rs:64:6
+  --> $DIR/lint-dead-code-1.rs:65:6
    |
 LL | enum priv_enum { foo2, bar2 }
    |      ^^^^^^^^^
 
 error: variant `bar3` is never constructed
-  --> $DIR/lint-dead-code-1.rs:67:5
+  --> $DIR/lint-dead-code-1.rs:68:5
    |
 LL | enum used_enum {
    |      --------- variant in this enum
@@ -38,25 +38,25 @@ LL |     bar3
    |     ^^^^
 
 error: function `priv_fn` is never used
-  --> $DIR/lint-dead-code-1.rs:88:4
+  --> $DIR/lint-dead-code-1.rs:90:4
    |
 LL | fn priv_fn() {
    |    ^^^^^^^
 
 error: function `foo` is never used
-  --> $DIR/lint-dead-code-1.rs:93:4
+  --> $DIR/lint-dead-code-1.rs:95:4
    |
 LL | fn foo() {
    |    ^^^
 
 error: function `bar` is never used
-  --> $DIR/lint-dead-code-1.rs:98:4
+  --> $DIR/lint-dead-code-1.rs:100:4
    |
 LL | fn bar() {
    |    ^^^
 
 error: function `baz` is never used
-  --> $DIR/lint-dead-code-1.rs:102:4
+  --> $DIR/lint-dead-code-1.rs:104:4
    |
 LL | fn baz() -> impl Copy {
    |    ^^^
diff --git a/tests/ui/lint/issue-106991.rs b/tests/ui/lint/issue-106991.rs
index e4d7f765b4a..b70f751195a 100644
--- a/tests/ui/lint/issue-106991.rs
+++ b/tests/ui/lint/issue-106991.rs
@@ -3,7 +3,7 @@ fn foo(items: &mut Vec<u8>) {
 }
 
 fn bar() -> impl Iterator<Item = i32> {
-    //~^ ERROR expected `foo` to be a fn item that returns `i32`, but it returns `()` [E0271]
+    //~^ ERROR expected `foo` to return `i32`, but it returns `()` [E0271]
     let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]];
     x.iter_mut().map(foo)
 }
diff --git a/tests/ui/lint/issue-106991.stderr b/tests/ui/lint/issue-106991.stderr
index 0441a6377d0..15e0ba5337f 100644
--- a/tests/ui/lint/issue-106991.stderr
+++ b/tests/ui/lint/issue-106991.stderr
@@ -1,4 +1,4 @@
-error[E0271]: expected `foo` to be a fn item that returns `i32`, but it returns `()`
+error[E0271]: expected `foo` to return `i32`, but it returns `()`
   --> $DIR/issue-106991.rs:5:13
    |
 LL | fn bar() -> impl Iterator<Item = i32> {
diff --git a/tests/ui/liveness/liveness-unused.rs b/tests/ui/liveness/liveness-unused.rs
index ba635e6638c..49e7044aeda 100644
--- a/tests/ui/liveness/liveness-unused.rs
+++ b/tests/ui/liveness/liveness-unused.rs
@@ -2,6 +2,7 @@
 #![deny(unused_variables)]
 #![deny(unused_assignments)]
 #![allow(dead_code, non_camel_case_types, trivial_numeric_casts, dropping_copy_types)]
+#![feature(intrinsics)]
 
 use std::ops::AddAssign;
 
@@ -137,5 +138,10 @@ fn f7() {
     drop(a);
 }
 
+// unused params warnings are not needed for intrinsic functions without bodies
+#[rustc_intrinsic]
+unsafe fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
+
+
 fn main() {
 }
diff --git a/tests/ui/liveness/liveness-unused.stderr b/tests/ui/liveness/liveness-unused.stderr
index f6c478ddbc7..a69fc10dff2 100644
--- a/tests/ui/liveness/liveness-unused.stderr
+++ b/tests/ui/liveness/liveness-unused.stderr
@@ -1,5 +1,5 @@
 warning: unreachable statement
-  --> $DIR/liveness-unused.rs:92:9
+  --> $DIR/liveness-unused.rs:93:9
    |
 LL |         continue;
    |         -------- any code following this expression is unreachable
@@ -14,7 +14,7 @@ LL | #![warn(unused)]
    = note: `#[warn(unreachable_code)]` implied by `#[warn(unused)]`
 
 error: unused variable: `x`
-  --> $DIR/liveness-unused.rs:8:7
+  --> $DIR/liveness-unused.rs:9:7
    |
 LL | fn f1(x: isize) {
    |       ^ help: if this is intentional, prefix it with an underscore: `_x`
@@ -26,25 +26,25 @@ LL | #![deny(unused_variables)]
    |         ^^^^^^^^^^^^^^^^
 
 error: unused variable: `x`
-  --> $DIR/liveness-unused.rs:12:8
+  --> $DIR/liveness-unused.rs:13:8
    |
 LL | fn f1b(x: &mut isize) {
    |        ^ help: if this is intentional, prefix it with an underscore: `_x`
 
 error: unused variable: `x`
-  --> $DIR/liveness-unused.rs:20:9
+  --> $DIR/liveness-unused.rs:21:9
    |
 LL |     let x: isize;
    |         ^ help: if this is intentional, prefix it with an underscore: `_x`
 
 error: unused variable: `x`
-  --> $DIR/liveness-unused.rs:25:9
+  --> $DIR/liveness-unused.rs:26:9
    |
 LL |     let x = 3;
    |         ^ help: if this is intentional, prefix it with an underscore: `_x`
 
 error: variable `x` is assigned to, but never used
-  --> $DIR/liveness-unused.rs:30:13
+  --> $DIR/liveness-unused.rs:31:13
    |
 LL |     let mut x = 3;
    |             ^
@@ -52,7 +52,7 @@ LL |     let mut x = 3;
    = note: consider using `_x` instead
 
 error: value assigned to `x` is never read
-  --> $DIR/liveness-unused.rs:32:5
+  --> $DIR/liveness-unused.rs:33:5
    |
 LL |     x += 4;
    |     ^
@@ -65,7 +65,7 @@ LL | #![deny(unused_assignments)]
    |         ^^^^^^^^^^^^^^^^^^
 
 error: variable `z` is assigned to, but never used
-  --> $DIR/liveness-unused.rs:37:13
+  --> $DIR/liveness-unused.rs:38:13
    |
 LL |     let mut z = 3;
    |             ^
@@ -73,31 +73,31 @@ LL |     let mut z = 3;
    = note: consider using `_z` instead
 
 error: unused variable: `i`
-  --> $DIR/liveness-unused.rs:59:12
+  --> $DIR/liveness-unused.rs:60:12
    |
 LL |       Some(i) => {
    |            ^ help: if this is intentional, prefix it with an underscore: `_i`
 
 error: unused variable: `x`
-  --> $DIR/liveness-unused.rs:79:9
+  --> $DIR/liveness-unused.rs:80:9
    |
 LL |     for x in 1..10 { }
    |         ^ help: if this is intentional, prefix it with an underscore: `_x`
 
 error: unused variable: `x`
-  --> $DIR/liveness-unused.rs:84:10
+  --> $DIR/liveness-unused.rs:85:10
    |
 LL |     for (x, _) in [1, 2, 3].iter().enumerate() { }
    |          ^ help: if this is intentional, prefix it with an underscore: `_x`
 
 error: unused variable: `x`
-  --> $DIR/liveness-unused.rs:89:13
+  --> $DIR/liveness-unused.rs:90:13
    |
 LL |     for (_, x) in [1, 2, 3].iter().enumerate() {
    |             ^ help: if this is intentional, prefix it with an underscore: `_x`
 
 error: variable `x` is assigned to, but never used
-  --> $DIR/liveness-unused.rs:112:9
+  --> $DIR/liveness-unused.rs:113:9
    |
 LL |     let x;
    |         ^
@@ -105,7 +105,7 @@ LL |     let x;
    = note: consider using `_x` instead
 
 error: value assigned to `x` is never read
-  --> $DIR/liveness-unused.rs:116:9
+  --> $DIR/liveness-unused.rs:117:9
    |
 LL |         x = 0;
    |         ^
diff --git a/tests/ui/mir/null/addrof_null.rs b/tests/ui/mir/null/addrof_null.rs
new file mode 100644
index 00000000000..0d0b7edeef6
--- /dev/null
+++ b/tests/ui/mir/null/addrof_null.rs
@@ -0,0 +1,14 @@
+// Make sure that we don't insert a check for `addr_of!`.
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+struct Field {
+    a: u32,
+}
+
+fn main() {
+    unsafe {
+        let ptr: *const Field = std::ptr::null();
+        let _ptr = core::ptr::addr_of!((*ptr).a);
+    }
+}
diff --git a/tests/ui/mir/null/borrowed_mut_null.rs b/tests/ui/mir/null/borrowed_mut_null.rs
new file mode 100644
index 00000000000..437955c452b
--- /dev/null
+++ b/tests/ui/mir/null/borrowed_mut_null.rs
@@ -0,0 +1,8 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: null pointer dereference occured
+
+fn main() {
+    let ptr: *mut u32 = std::ptr::null_mut();
+    let _ptr: &mut u32 = unsafe { &mut *ptr };
+}
diff --git a/tests/ui/mir/null/borrowed_null.rs b/tests/ui/mir/null/borrowed_null.rs
new file mode 100644
index 00000000000..eb0794efaa5
--- /dev/null
+++ b/tests/ui/mir/null/borrowed_null.rs
@@ -0,0 +1,8 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: null pointer dereference occured
+
+fn main() {
+    let ptr: *const u32 = std::ptr::null();
+    let _ptr: &u32 = unsafe { &*ptr };
+}
diff --git a/tests/ui/mir/null/null_lhs.rs b/tests/ui/mir/null/null_lhs.rs
new file mode 100644
index 00000000000..fd3bc3a78b8
--- /dev/null
+++ b/tests/ui/mir/null/null_lhs.rs
@@ -0,0 +1,10 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: null pointer dereference occured
+
+fn main() {
+    let ptr: *mut u32 = std::ptr::null_mut();
+    unsafe {
+        *(ptr) = 42;
+    }
+}
diff --git a/tests/ui/mir/null/null_rhs.rs b/tests/ui/mir/null/null_rhs.rs
new file mode 100644
index 00000000000..45c8beb3fe8
--- /dev/null
+++ b/tests/ui/mir/null/null_rhs.rs
@@ -0,0 +1,10 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: null pointer dereference occured
+
+fn main() {
+    let ptr: *mut u32 = std::ptr::null_mut();
+    unsafe {
+        let _v = *ptr;
+    }
+}
diff --git a/tests/ui/mir/null/place_without_read.rs b/tests/ui/mir/null/place_without_read.rs
new file mode 100644
index 00000000000..d6bfb089b01
--- /dev/null
+++ b/tests/ui/mir/null/place_without_read.rs
@@ -0,0 +1,10 @@
+// Make sure that we don't insert a check for places that do not read.
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+fn main() {
+    let ptr: *const u16 = std::ptr::null();
+    unsafe {
+        let _ = *ptr;
+    }
+}
diff --git a/tests/ui/mir/null/two_pointers.rs b/tests/ui/mir/null/two_pointers.rs
new file mode 100644
index 00000000000..d9f0687fe0d
--- /dev/null
+++ b/tests/ui/mir/null/two_pointers.rs
@@ -0,0 +1,12 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: null pointer dereference occured
+
+fn main() {
+    let ptr = std::ptr::null();
+    let mut dest = 0u32;
+    let dest_ptr = &mut dest as *mut u32;
+    unsafe {
+        *dest_ptr = *(ptr);
+    }
+}
diff --git a/tests/ui/mir/null/zero_sized_access.rs b/tests/ui/mir/null/zero_sized_access.rs
new file mode 100644
index 00000000000..e8aaf820c49
--- /dev/null
+++ b/tests/ui/mir/null/zero_sized_access.rs
@@ -0,0 +1,15 @@
+// Make sure that we don't insert a check for zero-sized reads or writes to
+// null, because they are allowed.
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+fn main() {
+    let ptr: *mut () = std::ptr::null_mut();
+    unsafe {
+        *(ptr) = ();
+    }
+    let ptr1: *const () = std::ptr::null_mut();
+    unsafe {
+        let _ptr = *ptr1;
+    }
+}
diff --git a/tests/ui/mut/mutable-class-fields-2.stderr b/tests/ui/mut/mutable-class-fields-2.stderr
index eb0c54f885b..7a6ff4da2bf 100644
--- a/tests/ui/mut/mutable-class-fields-2.stderr
+++ b/tests/ui/mut/mutable-class-fields-2.stderr
@@ -7,7 +7,7 @@ LL |     self.how_hungry -= 5;
 help: consider changing this to be a mutable reference
    |
 LL |   pub fn eat(&mut self) {
-   |              ~~~~~~~~~
+   |               +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr
index aa4a2760ffd..ac99a1fc24c 100644
--- a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr
+++ b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr
@@ -1,16 +1,15 @@
-error[E0271]: expected `{closure@fallback-closure-wrap.rs:18:40}` to be a closure that returns `()`, but it returns `!`
-  --> $DIR/fallback-closure-wrap.rs:18:31
+error[E0271]: expected `{closure@fallback-closure-wrap.rs:18:40}` to return `()`, but it returns `!`
+  --> $DIR/fallback-closure-wrap.rs:19:9
    |
-LL |       let error = Closure::wrap(Box::new(move || {
-   |  _______________________________^
-LL | |
-LL | |         panic!("Can't connect to server.");
-LL | |     }) as Box<dyn FnMut()>);
-   | |______^ expected `()`, found `!`
+LL |     let error = Closure::wrap(Box::new(move || {
+   |                                        ------- this closure
+LL |         panic!("Can't connect to server.");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!`
    |
    = note: expected unit type `()`
                    found type `!`
    = note: required for the cast from `Box<{closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47}>` to `Box<dyn FnMut()>`
+   = note: this error originates in the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/never_type/fallback-closure-wrap.rs b/tests/ui/never_type/fallback-closure-wrap.rs
index 27020289c68..e7f7d5aae3f 100644
--- a/tests/ui/never_type/fallback-closure-wrap.rs
+++ b/tests/ui/never_type/fallback-closure-wrap.rs
@@ -16,8 +16,8 @@ use std::marker::PhantomData;
 
 fn main() {
     let error = Closure::wrap(Box::new(move || {
-        //[fallback]~^ to be a closure that returns `()`, but it returns `!`
         panic!("Can't connect to server.");
+        //[fallback]~^ to return `()`, but it returns `!`
     }) as Box<dyn FnMut()>);
 }
 
diff --git a/tests/ui/pattern/issue-110508.rs b/tests/ui/pattern/issue-110508.rs
index 6ed0476183e..74a8d673e83 100644
--- a/tests/ui/pattern/issue-110508.rs
+++ b/tests/ui/pattern/issue-110508.rs
@@ -1,5 +1,7 @@
 //@ run-pass
 
+#![deny(dead_code)]
+
 #[derive(PartialEq, Eq)]
 pub enum Foo {
     FooA(()),
@@ -11,6 +13,7 @@ impl Foo {
     const A2: Foo = Self::FooA(());
     const A3: Self = Foo::FooA(());
     const A4: Self = Self::FooA(());
+    const A5: u32 = 1;
 }
 
 fn main() {
@@ -35,4 +38,9 @@ fn main() {
         Foo::A4 => {},
         _ => {},
     }
+
+    match 3 {
+        Foo::A5..5 => {}
+        _ => {}
+    }
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr
new file mode 100644
index 00000000000..331b86736a0
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr
@@ -0,0 +1,79 @@
+error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array
+  --> $DIR/borrowck-errors.rs:13:16
+   |
+LL |     let [&x] = &[&mut 0];
+   |           -    ^^^^^^^^^ cannot move out of here
+   |           |
+   |           data moved here
+   |           move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
+   |
+help: consider borrowing the pattern binding
+   |
+LL |     let [&ref x] = &[&mut 0];
+   |           +++
+
+error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array
+  --> $DIR/borrowck-errors.rs:19:16
+   |
+LL |     let [&x] = &mut [&mut 0];
+   |           -    ^^^^^^^^^^^^^ cannot move out of here
+   |           |
+   |           data moved here
+   |           move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
+   |
+help: consider borrowing the pattern binding
+   |
+LL |     let [&ref x] = &mut [&mut 0];
+   |           +++
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/borrowck-errors.rs:27:29
+   |
+LL |     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
+   |                       -     ^^^^^^^^^^^^^^^^^^^
+   |                       |
+   |                       data moved here
+   |                       move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
+LL +     if let Some(Some(x)) = Some(&Some(&mut 0)) {
+   |
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/borrowck-errors.rs:32:10
+   |
+LL |     let &ref mut x = &0;
+   |          ^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/borrowck-errors.rs:35:23
+   |
+LL |     if let &Some(Some(x)) = &Some(&mut Some(0)) {
+   |                       ^ cannot borrow as mutable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/borrowck-errors.rs:40:11
+   |
+LL |     let &[x] = &&mut [0];
+   |           ^ cannot borrow as mutable
+
+error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array
+  --> $DIR/borrowck-errors.rs:44:20
+   |
+LL |     let [&mut x] = &mut [&mut 0];
+   |               -    ^^^^^^^^^^^^^ cannot move out of here
+   |               |
+   |               data moved here
+   |               move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
+   |
+help: consider borrowing the pattern binding
+   |
+LL |     let [&mut ref x] = &mut [&mut 0];
+   |               +++
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0507, E0508, E0596.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs
index a01e9ca2657..3f5d9c8db5d 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs
@@ -1,9 +1,27 @@
-//@ edition: 2024
-//@ revisions: classic structural
+//@ revisions: stable2021 classic2024 structural2024
+//@[stable2021] edition: 2021
+//@[classic2024] edition: 2024
+//@[structural2024] edition: 2024
 //! Tests for pattern errors not handled by the pattern typing rules, but by borrowck.
 #![allow(incomplete_features)]
-#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
+
+/// These patterns additionally use `&` to match a `&mut` reference type, which causes compilation
+/// to fail in HIR typeck on stable. As such, they need to be separate from the other tests.
+fn errors_caught_in_hir_typeck_on_stable() {
+    let [&x] = &[&mut 0];
+    //[stable2021]~^ mismatched types
+    //[stable2021]~| types differ in mutability
+    //[classic2024]~^^^ ERROR: cannot move out of type
+    let _: &u32 = x;
+
+    let [&x] = &mut [&mut 0];
+    //[stable2021]~^ mismatched types
+    //[stable2021]~| types differ in mutability
+    //[classic2024]~^^^ ERROR: cannot move out of type
+    let _: &u32 = x;
+}
 
 pub fn main() {
     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
@@ -13,4 +31,18 @@ pub fn main() {
 
     let &ref mut x = &0;
     //~^ cannot borrow data in a `&` reference as mutable [E0596]
+
+    if let &Some(Some(x)) = &Some(&mut Some(0)) {
+        //[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable
+        let _: &u32 = x;
+    }
+
+    let &[x] = &&mut [0];
+    //[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable
+    let _: &u32 = x;
+
+    let [&mut x] = &mut [&mut 0];
+    //[classic2024]~^ ERROR: cannot move out of type
+    #[cfg(stable2021)] let _: u32 = x;
+    #[cfg(structural2024)] let _: &mut u32 = x;
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr
new file mode 100644
index 00000000000..65c98e2da9c
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr
@@ -0,0 +1,69 @@
+error[E0308]: mismatched types
+  --> $DIR/borrowck-errors.rs:13:10
+   |
+LL |     let [&x] = &[&mut 0];
+   |          ^^    --------- this expression has type `&[&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     let [&x] = &[&mut 0];
+LL +     let [x] = &[&mut 0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/borrowck-errors.rs:19:10
+   |
+LL |     let [&x] = &mut [&mut 0];
+   |          ^^    ------------- this expression has type `&mut [&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     let [&x] = &mut [&mut 0];
+LL +     let [x] = &mut [&mut 0];
+   |
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/borrowck-errors.rs:27:29
+   |
+LL |     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
+   |                       -     ^^^^^^^^^^^^^^^^^^^
+   |                       |
+   |                       data moved here
+   |                       move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
+LL +     if let Some(Some(x)) = Some(&Some(&mut 0)) {
+   |
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/borrowck-errors.rs:32:10
+   |
+LL |     let &ref mut x = &0;
+   |          ^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/borrowck-errors.rs:35:23
+   |
+LL |     if let &Some(Some(x)) = &Some(&mut Some(0)) {
+   |                       ^ cannot borrow as mutable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/borrowck-errors.rs:40:11
+   |
+LL |     let &[x] = &&mut [0];
+   |           ^ cannot borrow as mutable
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0507, E0596.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr
deleted file mode 100644
index c6246114075..00000000000
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0507]: cannot move out of a shared reference
-  --> $DIR/borrowck-errors.rs:9:29
-   |
-LL |     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
-   |                       -     ^^^^^^^^^^^^^^^^^^^
-   |                       |
-   |                       data moved here
-   |                       move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
-   |
-help: consider removing the borrow
-   |
-LL -     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
-LL +     if let Some(Some(x)) = Some(&Some(&mut 0)) {
-   |
-
-error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/borrowck-errors.rs:14:10
-   |
-LL |     let &ref mut x = &0;
-   |          ^^^^^^^^^ cannot borrow as mutable
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0507, E0596.
-For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr
index c6246114075..30d2f9f3d70 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of a shared reference
-  --> $DIR/borrowck-errors.rs:9:29
+  --> $DIR/borrowck-errors.rs:27:29
    |
 LL |     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
    |                       -     ^^^^^^^^^^^^^^^^^^^
@@ -14,7 +14,7 @@ LL +     if let Some(Some(x)) = Some(&Some(&mut 0)) {
    |
 
 error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/borrowck-errors.rs:14:10
+  --> $DIR/borrowck-errors.rs:32:10
    |
 LL |     let &ref mut x = &0;
    |          ^^^^^^^^^ cannot borrow as mutable
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic2024.stderr
index 89a52ba7d1d..89a52ba7d1d 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic2024.stderr
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs
index e22bd1f8f6c..a493b672c92 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs
@@ -1,9 +1,9 @@
 //@ edition: 2024
-//@ revisions: classic structural
+//@ revisions: classic2024 structural2024
 //! Test that `&mut` patterns don't match shared reference types under new typing rules in Rust 2024
 #![allow(incomplete_features)]
-#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     let &mut _ = &&0;
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural2024.stderr
index 89a52ba7d1d..89a52ba7d1d 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural2024.stderr
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic2024.stderr
index 43560a18030..afaa925a757 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic2024.stderr
@@ -1,5 +1,5 @@
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/mut-ref-mut.rs:11:13
+  --> $DIR/mut-ref-mut.rs:14:13
    |
 LL |     let Foo(mut a) = &Foo(0);
    |             ^^^^
@@ -9,7 +9,7 @@ LL |     let Foo(mut a) = &Foo(0);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/mut-ref-mut.rs:15:13
+  --> $DIR/mut-ref-mut.rs:19:13
    |
 LL |     let Foo(mut a) = &mut Foo(0);
    |             ^^^^
@@ -18,6 +18,19 @@ LL |     let Foo(mut a) = &mut Foo(0);
    = help: add `#![feature(mut_ref)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/mut-ref-mut.rs:24:10
+   |
+LL |     let [&mut mut x] = &[&mut 0];
+   |          ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let [&mut x] = &[&mut 0];
+   |          ~
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs
index 786587984ba..fbd6514df73 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs
@@ -1,18 +1,29 @@
-//@ edition: 2024
-//@ revisions: classic structural
+//@ revisions: stable2021 classic2024 structural2024
+//@[stable2021] edition: 2021
+//@[classic2024] edition: 2024
+//@[structural2024] edition: 2024
+//@[stable2021] run-pass
 //! Test diagnostics for binding with `mut` when the default binding mode is by-ref.
-#![allow(incomplete_features)]
-#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+#![allow(incomplete_features, unused_assignments, unused_variables)]
+#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     struct Foo(u8);
 
     let Foo(mut a) = &Foo(0);
-    //~^ ERROR: binding cannot be both mutable and by-reference
-    a = &42;
+    //[classic2024,structural2024]~^ ERROR: binding cannot be both mutable and by-reference
+    #[cfg(stable2021)] { a = 42 }
+    #[cfg(any(classic2024, structural2024))] { a = &42 }
 
     let Foo(mut a) = &mut Foo(0);
-    //~^ ERROR: binding cannot be both mutable and by-reference
-    a = &mut 42;
+    //[classic2024,structural2024]~^ ERROR: binding cannot be both mutable and by-reference
+    #[cfg(stable2021)] { a = 42 }
+    #[cfg(any(classic2024, structural2024))] { a = &mut 42 }
+
+    let [&mut mut x] = &[&mut 0];
+    //[classic2024]~^ ERROR: mismatched types
+    //[classic2024]~| cannot match inherited `&` with `&mut` pattern
+    //[structural2024]~^^^ binding cannot be both mutable and by-reference
+    #[cfg(stable2021)] { x = 0 }
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural2024.stderr
index 43560a18030..fd82da70a18 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural2024.stderr
@@ -1,5 +1,5 @@
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/mut-ref-mut.rs:11:13
+  --> $DIR/mut-ref-mut.rs:14:13
    |
 LL |     let Foo(mut a) = &Foo(0);
    |             ^^^^
@@ -9,7 +9,7 @@ LL |     let Foo(mut a) = &Foo(0);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/mut-ref-mut.rs:15:13
+  --> $DIR/mut-ref-mut.rs:19:13
    |
 LL |     let Foo(mut a) = &mut Foo(0);
    |             ^^^^
@@ -18,6 +18,16 @@ LL |     let Foo(mut a) = &mut Foo(0);
    = help: add `#![feature(mut_ref)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 2 previous errors
+error[E0658]: binding cannot be both mutable and by-reference
+  --> $DIR/mut-ref-mut.rs:24:15
+   |
+LL |     let [&mut mut x] = &[&mut 0];
+   |               ^^^^
+   |
+   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
+   = help: add `#![feature(mut_ref)]` 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 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2024.stderr
index 2bc3ecb7636..3a124dcead5 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2024.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:15:17
+  --> $DIR/pattern-errors.rs:12:17
    |
 LL |     if let Some(&mut x) = &Some(&mut 0) {
    |                 ^^^^^
@@ -11,7 +11,7 @@ LL |     if let Some(&x) = &Some(&mut 0) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:19:17
+  --> $DIR/pattern-errors.rs:18:17
    |
 LL |     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
    |                 ^^^^^
@@ -23,7 +23,7 @@ LL |     if let Some(&Some(&x)) = &Some(&mut Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:23:22
+  --> $DIR/pattern-errors.rs:24:22
    |
 LL |     if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
    |                      ^^^^^
@@ -35,7 +35,7 @@ LL |     if let Some(Some(&x)) = &Some(Some(&mut 0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:28:17
+  --> $DIR/pattern-errors.rs:31:17
    |
 LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
    |                 ^^^^^
@@ -47,65 +47,77 @@ LL |     if let Some(&Some(&_)) = &Some(&Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:31:23
+  --> $DIR/pattern-errors.rs:41:23
    |
-LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
+LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
    |                       ^^^^^
    |
    = note: cannot match inherited `&` with `&mut` pattern
 help: replace this `&mut` pattern with `&`
    |
-LL |     if let Some(&Some(&_)) = &Some(&mut Some(0)) {
+LL |     if let Some(&Some(&_)) = &mut Some(&Some(0)) {
    |                       ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:34:23
+  --> $DIR/pattern-errors.rs:51:17
    |
-LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
-   |                       ^^^^^
+LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^
    |
    = note: cannot match inherited `&` with `&mut` pattern
 help: replace this `&mut` pattern with `&`
    |
-LL |     if let Some(&Some(&_)) = &mut Some(&Some(0)) {
-   |                       ~
+LL |     if let Some(&Some(x)) = &Some(Some(0)) {
+   |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:37:29
+  --> $DIR/pattern-errors.rs:147:10
    |
-LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
-   |                             ^^^^^
+LL |     let [&mut x] = &[&mut 0];
+   |          ^^^^^
    |
    = note: cannot match inherited `&` with `&mut` pattern
 help: replace this `&mut` pattern with `&`
    |
-LL |     if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) {
-   |                             ~
+LL |     let [&x] = &[&mut 0];
+   |          ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:40:17
+  --> $DIR/pattern-errors.rs:153:10
    |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^
+LL |     let [&mut &x] = &[&mut 0];
+   |          ^^^^^
    |
    = note: cannot match inherited `&` with `&mut` pattern
 help: replace this `&mut` pattern with `&`
    |
-LL |     if let Some(&Some(x)) = &Some(Some(0)) {
-   |                 ~
+LL |     let [&&x] = &[&mut 0];
+   |          ~
 
 error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:43:17
+  --> $DIR/pattern-errors.rs:159:10
    |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^
+LL |     let [&mut &ref x] = &[&mut 0];
+   |          ^^^^^
    |
    = note: cannot match inherited `&` with `&mut` pattern
 help: replace this `&mut` pattern with `&`
    |
-LL |     if let Some(&Some(x)) = &Some(Some(0)) {
-   |                 ~
+LL |     let [&&ref x] = &[&mut 0];
+   |          ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:165:10
+   |
+LL |     let [&mut &(mut x)] = &[&mut 0];
+   |          ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let [&&(mut x)] = &[&mut 0];
+   |          ~
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs
index 3535ba9c701..c07c2972cd0 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs
@@ -1,46 +1,170 @@
-//@ edition: 2024
-//@ revisions: classic structural
+//@ revisions: stable2021 classic2024 structural2024
+//@[stable2021] edition: 2021
+//@[classic2024] edition: 2024
+//@[structural2024] edition: 2024
 //! Test cases for poorly-typed patterns in edition 2024 which are caught by HIR typeck. These must
 //! be separate from cases caught by MIR borrowck or the latter errors may not be emitted.
 #![allow(incomplete_features)]
-#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
-    if let Some(&mut x) = &mut Some(&0) {
-        //[structural]~^ ERROR: mismatched types
-        let _: &u32 = x;
-    }
-
     if let Some(&mut x) = &Some(&mut 0) {
-        //[classic]~^ ERROR: mismatched types
-        let _: &u32 = x;
+        //[classic2024]~^ ERROR: mismatched types
+        //[classic2024]~| cannot match inherited `&` with `&mut` pattern
+        #[cfg(stable2021)] let _: u32 = x;
+        #[cfg(structural2024)] let _: &u32 = x;
     }
     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
-        //[classic]~^ ERROR: mismatched types
+        //[stable2021,classic2024]~^ ERROR: mismatched types
+        //[stable2021]~| expected integer, found `&_`
+        //[classic2024]~| cannot match inherited `&` with `&mut` pattern
         let _: u32 = x;
     }
     if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
-        //[classic]~^ ERROR: mismatched types
-        let _: &u32 = x;
+        //[classic2024]~^ ERROR: mismatched types
+        //[classic2024]~| cannot match inherited `&` with `&mut` pattern
+        #[cfg(stable2021)] let _: u32 = x;
+        #[cfg(structural2024)] let _: &u32 = x;
     }
 
     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
         //~^ ERROR: mismatched types
+        //[stable2021]~| types differ in mutability
+        //[classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern
     }
     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
-        //~^ ERROR: mismatched types
+        //[stable2021,structural2024]~^ ERROR: mismatched types
+        //[stable2021]~| types differ in mutability
+        //[structural2024]~| cannot match inherited `&` with `&mut` pattern
     }
     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
         //~^ ERROR: mismatched types
+        //[stable2021]~| expected integer, found `&mut _`
+        //[classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern
     }
-    if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
-        //~^ ERROR: mismatched types
-    }
-    if let Some(&mut Some(x)) = &Some(Some(0)) {
-        //~^ ERROR: mismatched types
+    if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) {
+        //[stable2021,structural2024]~^ ERROR: mismatched types
+        //[stable2021]~| expected `Option<&mut Option<{integer}>>`, found `&_`
+        //[structural2024]~| cannot match inherited `&` with `&mut` pattern
     }
     if let Some(&mut Some(x)) = &Some(Some(0)) {
         //~^ ERROR: mismatched types
+        //[stable2021]~| expected `Option<{integer}>`, found `&mut _`
+        //[classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern
     }
 }
+
+fn structural_errors_0() {
+    let &[&mut x] = &&mut [0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| expected integer, found `&mut _`
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+
+    let &[&mut x] = &mut &mut [0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+
+    let &[&mut ref x] = &&mut [0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| expected integer, found `&mut _`
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: &u32 = x;
+
+    let &[&mut ref x] = &mut &mut [0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: &u32 = x;
+
+    let &[&mut mut x] = &&mut [0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| expected integer, found `&mut _`
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+
+    let &[&mut mut x] = &mut &mut [0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+}
+
+fn structural_errors_1() {
+    let [&(mut x)] = &[&0];
+    //[structural2024]~^ ERROR: binding cannot be both mutable and by-reference
+    #[cfg(stable2021)] let _: u32 = x;
+    #[cfg(classic2024)] let _: &u32 = x;
+
+    let [&(mut x)] = &mut [&0];
+    //[structural2024]~^ ERROR: binding cannot be both mutable and by-reference
+    #[cfg(stable2021)] let _: u32 = x;
+    #[cfg(classic2024)] let _: &u32 = x;
+}
+
+fn structural_errors_2() {
+    let [&&mut x] = &[&mut 0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+
+    let [&&mut x] = &mut [&mut 0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+
+    let [&&mut ref x] = &[&mut 0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: &u32 = x;
+
+    let [&&mut ref x] = &mut [&mut 0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: &u32 = x;
+
+    let [&&mut mut x] = &[&mut 0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+
+    let [&&mut mut x] = &mut [&mut 0];
+    //[stable2021,structural2024]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+}
+
+fn classic_errors_0() {
+    let [&mut x] = &[&mut 0];
+    //[classic2024]~^ ERROR: mismatched types
+    //[classic2024]~| cannot match inherited `&` with `&mut` pattern
+    #[cfg(stable2021)] let _: u32 = x;
+    #[cfg(structural2024)] let _: &u32 = x;
+
+    let [&mut &x] = &[&mut 0];
+    //[stable2021,classic2024]~^ ERROR: mismatched types
+    //[stable2021]~| expected integer, found `&_`
+    //[classic2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+
+    let [&mut &ref x] = &[&mut 0];
+    //[stable2021,classic2024]~^ ERROR: mismatched types
+    //[stable2021]~| expected integer, found `&_`
+    //[classic2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: &u32 = x;
+
+    let [&mut &(mut x)] = &[&mut 0];
+    //[stable2021,classic2024]~^ ERROR: mismatched types
+    //[stable2021]~| expected integer, found `&_`
+    //[classic2024]~| cannot match inherited `&` with `&mut` pattern
+    let _: u32 = x;
+}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr
new file mode 100644
index 00000000000..e7eb1813846
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr
@@ -0,0 +1,283 @@
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:18:27
+   |
+LL |     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
+   |                           ^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
+   |                           |
+   |                           expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
+   |                           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:31:17
+   |
+LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
+   |                 ^^^^^^^^^^^^^    --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                 |
+   |                 types differ in mutability
+   |
+   = note:      expected reference `&Option<{integer}>`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:36:17
+   |
+LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
+   |                 ^^^^^^^^^^^^^    ------------------- this expression has type `&Option<&mut Option<{integer}>>`
+   |                 |
+   |                 types differ in mutability
+   |
+   = note: expected mutable reference `&mut Option<{integer}>`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:41:23
+   |
+LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
+   |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
+   |                       |
+   |                       expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:46:17
+   |
+LL |     if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) {
+   |                 ^^^^^^^^^^^^^^^^^^^    ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
+   |                 |
+   |                 expected `Option<&mut Option<{integer}>>`, found `&_`
+   |
+   = note:   expected enum `Option<&mut Option<{integer}>>`
+           found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:51:17
+   |
+LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&mut _`
+   |
+   = note:           expected enum `Option<{integer}>`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:59:11
+   |
+LL |     let &[&mut x] = &&mut [0];
+   |           ^^^^^^    --------- this expression has type `&&mut [{integer}; 1]`
+   |           |
+   |           expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/pattern-errors.rs:59:11
+   |
+LL |     let &[&mut x] = &&mut [0];
+   |           ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -     let &[&mut x] = &&mut [0];
+LL +     let &[x] = &&mut [0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:65:9
+   |
+LL |     let &[&mut x] = &mut &mut [0];
+   |         ^^^^^^^^^   ------------- this expression has type `&mut &mut [{integer}; 1]`
+   |         |
+   |         types differ in mutability
+   |
+   = note: expected mutable reference `&mut &mut [{integer}; 1]`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:71:11
+   |
+LL |     let &[&mut ref x] = &&mut [0];
+   |           ^^^^^^^^^^    --------- this expression has type `&&mut [{integer}; 1]`
+   |           |
+   |           expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/pattern-errors.rs:71:11
+   |
+LL |     let &[&mut ref x] = &&mut [0];
+   |           ^^^^^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -     let &[&mut ref x] = &&mut [0];
+LL +     let &[ref x] = &&mut [0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:77:9
+   |
+LL |     let &[&mut ref x] = &mut &mut [0];
+   |         ^^^^^^^^^^^^^   ------------- this expression has type `&mut &mut [{integer}; 1]`
+   |         |
+   |         types differ in mutability
+   |
+   = note: expected mutable reference `&mut &mut [{integer}; 1]`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:83:11
+   |
+LL |     let &[&mut mut x] = &&mut [0];
+   |           ^^^^^^^^^^    --------- this expression has type `&&mut [{integer}; 1]`
+   |           |
+   |           expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/pattern-errors.rs:83:11
+   |
+LL |     let &[&mut mut x] = &&mut [0];
+   |           ^^^^^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -     let &[&mut mut x] = &&mut [0];
+LL +     let &[mut x] = &&mut [0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:89:9
+   |
+LL |     let &[&mut mut x] = &mut &mut [0];
+   |         ^^^^^^^^^^^^^   ------------- this expression has type `&mut &mut [{integer}; 1]`
+   |         |
+   |         types differ in mutability
+   |
+   = note: expected mutable reference `&mut &mut [{integer}; 1]`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:109:10
+   |
+LL |     let [&&mut x] = &[&mut 0];
+   |          ^^^^^^^    --------- this expression has type `&[&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:115:10
+   |
+LL |     let [&&mut x] = &mut [&mut 0];
+   |          ^^^^^^^    ------------- this expression has type `&mut [&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:121:10
+   |
+LL |     let [&&mut ref x] = &[&mut 0];
+   |          ^^^^^^^^^^^    --------- this expression has type `&[&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:127:10
+   |
+LL |     let [&&mut ref x] = &mut [&mut 0];
+   |          ^^^^^^^^^^^    ------------- this expression has type `&mut [&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:133:10
+   |
+LL |     let [&&mut mut x] = &[&mut 0];
+   |          ^^^^^^^^^^^    --------- this expression has type `&[&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:139:10
+   |
+LL |     let [&&mut mut x] = &mut [&mut 0];
+   |          ^^^^^^^^^^^    ------------- this expression has type `&mut [&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:153:15
+   |
+LL |     let [&mut &x] = &[&mut 0];
+   |               ^^    --------- this expression has type `&[&mut {integer}; 1]`
+   |               |
+   |               expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     let [&mut &x] = &[&mut 0];
+LL +     let [&mut x] = &[&mut 0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:159:15
+   |
+LL |     let [&mut &ref x] = &[&mut 0];
+   |               ^^^^^^    --------- this expression has type `&[&mut {integer}; 1]`
+   |               |
+   |               expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     let [&mut &ref x] = &[&mut 0];
+LL +     let [&mut ref x] = &[&mut 0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:165:15
+   |
+LL |     let [&mut &(mut x)] = &[&mut 0];
+   |               ^^^^^^^^    --------- this expression has type `&[&mut {integer}; 1]`
+   |               |
+   |               expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     let [&mut &(mut x)] = &[&mut 0];
+LL +     let [&mut mut x)] = &[&mut 0];
+   |
+
+error: aborting due to 21 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr
deleted file mode 100644
index 59d65553fae..00000000000
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr
+++ /dev/null
@@ -1,89 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:10:17
-   |
-LL |     if let Some(&mut x) = &mut Some(&0) {
-   |                 ^^^^^^    ------------- this expression has type `&mut Option<&{integer}>`
-   |                 |
-   |                 types differ in mutability
-   |
-   = note:      expected reference `&{integer}`
-           found mutable reference `&mut _`
-note: to declare a mutable binding use: `mut x`
-  --> $DIR/pattern-errors.rs:10:17
-   |
-LL |     if let Some(&mut x) = &mut Some(&0) {
-   |                 ^^^^^^
-help: consider removing `&mut` from the pattern
-   |
-LL |     if let Some(x) = &mut Some(&0) {
-   |                 ~
-
-error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:28:17
-   |
-LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
-   |                 ^^^^^^^^^^^^^    --------------- this expression has type `&Option<&Option<{integer}>>`
-   |                 |
-   |                 types differ in mutability
-   |
-   = note:      expected reference `&Option<{integer}>`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:31:23
-   |
-LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
-   |                       ^^^^^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
-   |                       |
-   |                       expected integer, found `&mut _`
-   |
-   = note:           expected type `{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:34:23
-   |
-LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
-   |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
-   |                       |
-   |                       expected integer, found `&mut _`
-   |
-   = note:           expected type `{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:37:29
-   |
-LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
-   |                             ^^^^^^       ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
-   |                             |
-   |                             expected integer, found `&mut _`
-   |
-   = note:           expected type `{integer}`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:40:17
-   |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
-   |                 |
-   |                 expected `Option<{integer}>`, found `&mut _`
-   |
-   = note:           expected enum `Option<{integer}>`
-           found mutable reference `&mut _`
-
-error[E0308]: mismatched types
-  --> $DIR/pattern-errors.rs:43:17
-   |
-LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
-   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
-   |                 |
-   |                 expected `Option<{integer}>`, found `&mut _`
-   |
-   = note:           expected enum `Option<{integer}>`
-           found mutable reference `&mut _`
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr
new file mode 100644
index 00000000000..861ed2216cd
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr
@@ -0,0 +1,228 @@
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:31:17
+   |
+LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
+   |                 ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(&_)) = &Some(&Some(0)) {
+   |                 ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:36:23
+   |
+LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
+   |                       ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(&_)) = &Some(&mut Some(0)) {
+   |                       ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:41:23
+   |
+LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
+   |                       ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(&_)) = &mut Some(&Some(0)) {
+   |                       ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:46:28
+   |
+LL |     if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) {
+   |                            ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(Some(&_))) = &Some(Some(&mut Some(0))) {
+   |                            ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:51:17
+   |
+LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     if let Some(&Some(x)) = &Some(Some(0)) {
+   |                 ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:59:11
+   |
+LL |     let &[&mut x] = &&mut [0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let &[&x] = &&mut [0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:65:11
+   |
+LL |     let &[&mut x] = &mut &mut [0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let &[&x] = &mut &mut [0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:71:11
+   |
+LL |     let &[&mut ref x] = &&mut [0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let &[&ref x] = &&mut [0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:77:11
+   |
+LL |     let &[&mut ref x] = &mut &mut [0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let &[&ref x] = &mut &mut [0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:83:11
+   |
+LL |     let &[&mut mut x] = &&mut [0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let &[&mut x] = &&mut [0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:89:11
+   |
+LL |     let &[&mut mut x] = &mut &mut [0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let &[&mut x] = &mut &mut [0];
+   |           ~
+
+error[E0658]: binding cannot be both mutable and by-reference
+  --> $DIR/pattern-errors.rs:97:12
+   |
+LL |     let [&(mut x)] = &[&0];
+   |            ^^^^
+   |
+   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
+   = help: add `#![feature(mut_ref)]` 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]: binding cannot be both mutable and by-reference
+  --> $DIR/pattern-errors.rs:102:12
+   |
+LL |     let [&(mut x)] = &mut [&0];
+   |            ^^^^
+   |
+   = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information
+   = help: add `#![feature(mut_ref)]` 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[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:109:11
+   |
+LL |     let [&&mut x] = &[&mut 0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let [&&x] = &[&mut 0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:115:11
+   |
+LL |     let [&&mut x] = &mut [&mut 0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let [&&x] = &mut [&mut 0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:121:11
+   |
+LL |     let [&&mut ref x] = &[&mut 0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let [&&ref x] = &[&mut 0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:127:11
+   |
+LL |     let [&&mut ref x] = &mut [&mut 0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let [&&ref x] = &mut [&mut 0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:133:11
+   |
+LL |     let [&&mut mut x] = &[&mut 0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let [&&mut x] = &[&mut 0];
+   |           ~
+
+error[E0308]: mismatched types
+  --> $DIR/pattern-errors.rs:139:11
+   |
+LL |     let [&&mut mut x] = &mut [&mut 0];
+   |           ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let [&&mut x] = &mut [&mut 0];
+   |           ~
+
+error: aborting due to 19 previous errors
+
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr
new file mode 100644
index 00000000000..70cdcbd62eb
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr
@@ -0,0 +1,70 @@
+error[E0308]: mismatched types
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:60:10
+   |
+LL |     let [&mut ref x] = &[&mut 0];
+   |          ^^^^^
+   |
+   = note: cannot match inherited `&` with `&mut` pattern
+help: replace this `&mut` pattern with `&`
+   |
+LL |     let [&ref x] = &[&mut 0];
+   |          ~
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+   |
+LL |     let [ref mut x] = &[0];
+   |          ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &[ref mut x] = &[0];
+   |         +
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+   |
+LL |     let [ref mut x] = &[0];
+   |          ^^^^^^^^^ cannot borrow as mutable
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10
+   |
+LL |     let [ref x] = &[0];
+   |          ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &[ref x] = &[0];
+   |         +
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:88:10
+   |
+LL |     let [ref x] = &mut [0];
+   |          ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &mut [ref x] = &mut [0];
+   |         ++++
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:93:10
+   |
+LL |     let [ref mut x] = &mut [0];
+   |          ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &mut [ref mut x] = &mut [0];
+   |         ++++
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0596.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs
new file mode 100644
index 00000000000..4c88c0c63ae
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs
@@ -0,0 +1,97 @@
+//@ revisions: stable2021 classic2024 structural2024
+//@[stable2021] edition: 2021
+//@[classic2024] edition: 2024
+//@[structural2024] edition: 2024
+//! Tests for errors from binding with `ref x` under a by-ref default binding mode in edition 2024.
+//! These can't be in the same body as tests for other errors, since they're emitted during THIR
+//! construction. The errors on stable edition 2021 Rust are unrelated.
+#![allow(incomplete_features)]
+#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
+
+/// These only fail on the eat-inner variant of the new edition 2024 pattern typing rules.
+/// The eat-outer variant eats the inherited reference, so binding with `ref` isn't a problem.
+fn errors_from_eating_the_real_reference() {
+    let [&ref x] = &[&0];
+    //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(stable2021)] let _: &u32 = x;
+    #[cfg(classic2024)] let _: &&u32 = x;
+
+    let [&ref x] = &mut [&0];
+    //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(stable2021)] let _: &u32 = x;
+    #[cfg(classic2024)] let _: &&u32 = x;
+
+    let [&mut ref x] = &mut [&mut 0];
+    //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(stable2021)] let _: &u32 = x;
+    #[cfg(classic2024)] let _: &&mut u32 = x;
+
+    let [&mut ref mut x] = &mut [&mut 0];
+    //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(stable2021)] let _: &mut u32 = x;
+    #[cfg(classic2024)] let _: &mut &mut u32 = x;
+}
+
+/// To make absolutely sure binding with `ref` ignores inherited references on stable, let's
+/// quarantine these typeck errors (from using a `&` pattern to match a `&mut` reference type).
+fn errors_from_eating_the_real_reference_caught_in_hir_typeck_on_stable() {
+    let [&ref x] = &[&mut 0];
+    //[stable2021]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~^^^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(classic2024)] let _: &&mut u32 = x;
+
+    let [&ref x] = &mut [&mut 0];
+    //[stable2021]~^ ERROR: mismatched types
+    //[stable2021]~| types differ in mutability
+    //[structural2024]~^^^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(classic2024)] let _: &&mut u32 = x;
+}
+
+/// This one also needs to be quarantined for a typeck error on `classic2024` (eat-outer).
+fn errors_dependent_on_eating_order_caught_in_hir_typeck_when_eating_outer() {
+    let [&mut ref x] = &[&mut 0];
+    //[classic2024]~^ ERROR: mismatched types
+    //[classic2024]~| cannot match inherited `&` with `&mut` pattern
+    //[structural2024]~^^^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(stable2021)] let _: &u32 = x;
+}
+
+/// These should be errors in all editions. In edition 2024, they should be caught by the pattern
+/// typing rules disallowing `ref` when there's an inherited reference. In old editions where that
+/// resets the binding mode, they're borrowck errors due to binding with `ref mut`.
+/// As a quirk of how the edition 2024 error is emitted during THIR construction, it ends up going
+/// through borrowck as well, using the old `ref` behavior as a fallback, so we get that error too.
+fn borrowck_errors_in_old_editions() {
+    let [ref mut x] = &[0];
+    //~^ ERROR: cannot borrow data in a `&` reference as mutable
+    //[classic2024,structural2024]~| ERROR: this pattern relies on behavior which may change in edition 2024
+    //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default
+}
+
+/// The remaining tests are purely for testing `ref` bindings in the presence of an inherited
+/// reference. These should always fail on edition 2024 and succeed on edition 2021.
+pub fn main() {
+    let [ref x] = &[0];
+    //[classic2024,structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(stable2021)] let _: &u32 = x;
+
+    let [ref x] = &mut [0];
+    //[classic2024,structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(stable2021)] let _: &u32 = x;
+
+    let [ref mut x] = &mut [0];
+    //[classic2024,structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024
+    //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default
+    #[cfg(stable2021)] let _: &mut u32 = x;
+}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr
new file mode 100644
index 00000000000..a21e4bb5b8f
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr
@@ -0,0 +1,42 @@
+error[E0308]: mismatched types
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:43:10
+   |
+LL |     let [&ref x] = &[&mut 0];
+   |          ^^^^^^    --------- this expression has type `&[&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     let [&ref x] = &[&mut 0];
+LL +     let [ref x] = &[&mut 0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:50:10
+   |
+LL |     let [&ref x] = &mut [&mut 0];
+   |          ^^^^^^    ------------- this expression has type `&mut [&mut {integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     let [&ref x] = &mut [&mut 0];
+LL +     let [ref x] = &mut [&mut 0];
+   |
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+   |
+LL |     let [ref mut x] = &[0];
+   |          ^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0596.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr
new file mode 100644
index 00000000000..ee2c831bfcc
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr
@@ -0,0 +1,141 @@
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:15:11
+   |
+LL |     let [&ref x] = &[&0];
+   |           ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &[&ref x] = &[&0];
+   |         +
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:21:11
+   |
+LL |     let [&ref x] = &mut [&0];
+   |           ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &mut [&ref x] = &mut [&0];
+   |         ++++
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:27:15
+   |
+LL |     let [&mut ref x] = &mut [&mut 0];
+   |               ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &mut [&mut ref x] = &mut [&mut 0];
+   |         ++++
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:33:15
+   |
+LL |     let [&mut ref mut x] = &mut [&mut 0];
+   |               ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &mut [&mut ref mut x] = &mut [&mut 0];
+   |         ++++
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:43:11
+   |
+LL |     let [&ref x] = &[&mut 0];
+   |           ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &[&ref x] = &[&mut 0];
+   |         +
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:50:11
+   |
+LL |     let [&ref x] = &mut [&mut 0];
+   |           ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &mut [&ref x] = &mut [&mut 0];
+   |         ++++
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:60:15
+   |
+LL |     let [&mut ref x] = &[&mut 0];
+   |               ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &[&mut ref x] = &[&mut 0];
+   |         +
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+   |
+LL |     let [ref mut x] = &[0];
+   |          ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &[ref mut x] = &[0];
+   |         +
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10
+   |
+LL |     let [ref mut x] = &[0];
+   |          ^^^^^^^^^ cannot borrow as mutable
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10
+   |
+LL |     let [ref x] = &[0];
+   |          ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &[ref x] = &[0];
+   |         +
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:88:10
+   |
+LL |     let [ref x] = &mut [0];
+   |          ^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &mut [ref x] = &mut [0];
+   |         ++++
+
+error: this pattern relies on behavior which may change in edition 2024
+  --> $DIR/ref-binding-on-inh-ref-errors.rs:93:10
+   |
+LL |     let [ref mut x] = &mut [0];
+   |          ^^^^^^^ cannot override to bind by-reference when that is the implicit default
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
+help: make the implied reference pattern explicit
+   |
+LL |     let &mut [ref mut x] = &mut [0];
+   |         ++++
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed
deleted file mode 100644
index 4f4941975d8..00000000000
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed
+++ /dev/null
@@ -1,33 +0,0 @@
-//@ edition: 2024
-//@ run-rustfix
-//@ revisions: classic structural
-//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts
-//! to bind by mutable reference.
-#![allow(incomplete_features)]
-#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
-
-pub fn main() {
-    if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) {
-        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
-        let _: &mut u8 = x;
-    }
-
-    if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) {
-        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
-        let _: &mut u8 = x;
-    }
-
-    macro_rules! pat {
-        ($var:ident) => { ref mut $var };
-    }
-    let &mut pat!(x) = &mut 0;
-    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
-    let _: &mut u8 = x;
-
-    let &mut (ref mut a, ref mut b) = &mut (true, false);
-    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
-    //~| ERROR: cannot borrow as mutable inside an `&` pattern
-    let _: &mut bool = a;
-    let _: &mut bool = b;
-}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed
new file mode 100644
index 00000000000..c01784d5076
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed
@@ -0,0 +1,45 @@
+//@ revisions: stable2021 classic2024 structural2024
+//@[stable2021] edition: 2021
+//@[classic2024] edition: 2024
+//@[structural2024] edition: 2024
+//@[classic2024] run-rustfix
+//@[structural2024] run-rustfix
+//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts
+//! to bind by mutable reference.
+#![allow(incomplete_features)]
+#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
+
+pub fn main() {
+    if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) {
+        //[stable2021]~^ ERROR: mismatched types
+        //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) {
+        //[stable2021]~^ ERROR: mismatched types
+        //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    macro_rules! pat {
+        ($var:ident) => { ref mut $var };
+    }
+    let &mut pat!(x) = &mut 0;
+    //[stable2021]~^ ERROR: mismatched types
+    //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut u8 = x;
+
+    let &mut (ref mut a, ref mut b) = &mut (true, false);
+    //[stable2021]~^ ERROR: mismatched types
+    //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+    //[classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut bool = a;
+    let _: &mut bool = b;
+
+    let &mut [x] = &mut &mut [0];
+    //[stable2021]~^ ERROR: mismatched types
+    //[classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &u32 = x;
+}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.stderr
index 6c384a51fac..5e98b77be40 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.stderr
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:11:31
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:14:31
    |
 LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
    |                 -             ^
@@ -7,7 +7,7 @@ LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
    |                 help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:20:31
    |
 LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
    |            -                  ^
@@ -15,7 +15,7 @@ LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
    |            help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:24:15
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:29:15
    |
 LL |     let &pat!(x) = &mut 0;
    |         -     ^
@@ -23,7 +23,7 @@ LL |     let &pat!(x) = &mut 0;
    |         help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:19
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:19
    |
 LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         -         ^
@@ -31,13 +31,21 @@ LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:30
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:30
    |
 LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         -                    ^
    |         |
    |         help: replace this `&` with `&mut`: `&mut`
 
-error: aborting due to 5 previous errors
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:41:11
+   |
+LL |     let &[x] = &mut &mut [0];
+   |         - ^
+   |         |
+   |         help: replace this `&` with `&mut`: `&mut`
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs
index b29bff7603f..fe40dabb553 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs
@@ -1,20 +1,25 @@
-//@ edition: 2024
-//@ run-rustfix
-//@ revisions: classic structural
+//@ revisions: stable2021 classic2024 structural2024
+//@[stable2021] edition: 2021
+//@[classic2024] edition: 2024
+//@[structural2024] edition: 2024
+//@[classic2024] run-rustfix
+//@[structural2024] run-rustfix
 //! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts
 //! to bind by mutable reference.
 #![allow(incomplete_features)]
-#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
-        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+        //[stable2021]~^ ERROR: mismatched types
+        //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
         let _: &mut u8 = x;
     }
 
     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
-        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+        //[stable2021]~^ ERROR: mismatched types
+        //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
         let _: &mut u8 = x;
     }
 
@@ -22,12 +27,19 @@ pub fn main() {
         ($var:ident) => { ref mut $var };
     }
     let &pat!(x) = &mut 0;
-    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+    //[stable2021]~^ ERROR: mismatched types
+    //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
     let _: &mut u8 = x;
 
     let &(ref mut a, ref mut b) = &mut (true, false);
-    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
-    //~| ERROR: cannot borrow as mutable inside an `&` pattern
+    //[stable2021]~^ ERROR: mismatched types
+    //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+    //[classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern
     let _: &mut bool = a;
     let _: &mut bool = b;
+
+    let &[x] = &mut &mut [0];
+    //[stable2021]~^ ERROR: mismatched types
+    //[classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &u32 = x;
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr
new file mode 100644
index 00000000000..72c6c05e184
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr
@@ -0,0 +1,58 @@
+error[E0308]: mismatched types
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:14:17
+   |
+LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
+   |                 ^^^^^^^^^^^^^^^^    ------------------ this expression has type `&mut Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&_`
+   |
+   = note:   expected enum `Option<{integer}>`
+           found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:20:12
+   |
+LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
+   |            ^^^^^^^^^^^^^^^^^^^^^^   ------------------ this expression has type `&mut Option<Option<{integer}>>`
+   |            |
+   |            types differ in mutability
+   |
+   = note: expected mutable reference `&mut Option<Option<{integer}>>`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:29:9
+   |
+LL |     let &pat!(x) = &mut 0;
+   |         ^^^^^^^^   ------ this expression has type `&mut {integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:9
+   |
+LL |     let &(ref mut a, ref mut b) = &mut (true, false);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^   ------------------ this expression has type `&mut (bool, bool)`
+   |         |
+   |         types differ in mutability
+   |
+   = note: expected mutable reference `&mut (bool, bool)`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:41:9
+   |
+LL |     let &[x] = &mut &mut [0];
+   |         ^^^^   ------------- this expression has type `&mut &mut [{integer}; 1]`
+   |         |
+   |         types differ in mutability
+   |
+   = note: expected mutable reference `&mut &mut [{integer}; 1]`
+                      found reference `&_`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed
deleted file mode 100644
index 4f4941975d8..00000000000
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed
+++ /dev/null
@@ -1,33 +0,0 @@
-//@ edition: 2024
-//@ run-rustfix
-//@ revisions: classic structural
-//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts
-//! to bind by mutable reference.
-#![allow(incomplete_features)]
-#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
-
-pub fn main() {
-    if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) {
-        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
-        let _: &mut u8 = x;
-    }
-
-    if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) {
-        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
-        let _: &mut u8 = x;
-    }
-
-    macro_rules! pat {
-        ($var:ident) => { ref mut $var };
-    }
-    let &mut pat!(x) = &mut 0;
-    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
-    let _: &mut u8 = x;
-
-    let &mut (ref mut a, ref mut b) = &mut (true, false);
-    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
-    //~| ERROR: cannot borrow as mutable inside an `&` pattern
-    let _: &mut bool = a;
-    let _: &mut bool = b;
-}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed
new file mode 100644
index 00000000000..4ee849b38c5
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed
@@ -0,0 +1,45 @@
+//@ revisions: stable2021 classic2024 structural2024
+//@[stable2021] edition: 2021
+//@[classic2024] edition: 2024
+//@[structural2024] edition: 2024
+//@[classic2024] run-rustfix
+//@[structural2024] run-rustfix
+//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts
+//! to bind by mutable reference.
+#![allow(incomplete_features)]
+#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
+
+pub fn main() {
+    if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) {
+        //[stable2021]~^ ERROR: mismatched types
+        //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) {
+        //[stable2021]~^ ERROR: mismatched types
+        //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    macro_rules! pat {
+        ($var:ident) => { ref mut $var };
+    }
+    let &mut pat!(x) = &mut 0;
+    //[stable2021]~^ ERROR: mismatched types
+    //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut u8 = x;
+
+    let &mut (ref mut a, ref mut b) = &mut (true, false);
+    //[stable2021]~^ ERROR: mismatched types
+    //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+    //[classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut bool = a;
+    let _: &mut bool = b;
+
+    let &[x] = &mut &mut [0];
+    //[stable2021]~^ ERROR: mismatched types
+    //[classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &u32 = x;
+}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.stderr
index 6c384a51fac..69cb6c438b6 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.stderr
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:11:31
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:14:31
    |
 LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
    |                 -             ^
@@ -7,7 +7,7 @@ LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
    |                 help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:20:31
    |
 LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
    |            -                  ^
@@ -15,7 +15,7 @@ LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
    |            help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:24:15
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:29:15
    |
 LL |     let &pat!(x) = &mut 0;
    |         -     ^
@@ -23,7 +23,7 @@ LL |     let &pat!(x) = &mut 0;
    |         help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:19
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:19
    |
 LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         -         ^
@@ -31,7 +31,7 @@ LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:30
+  --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:30
    |
 LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         -                    ^
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs
index 9372049a2b2..ab3264704ac 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs
@@ -6,9 +6,11 @@
 #![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
+    #[cfg(structural)]
     if let &Some(Some(x)) = &Some(&mut Some(0)) {
         let _: &u32 = x;
     }
+
     if let Some(&x) = Some(&mut 0) {
         let _: u32 = x;
     }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs
index 077b52d8f27..3114b9d3bf8 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs
@@ -1,59 +1,127 @@
-//@ edition: 2024
-//@ revisions: classic structural
-//@ run-pass
+//@ revisions: stable2021 classic2024 structural2024
+//@[stable2021] edition: 2021
+//@[classic2024] edition: 2024
+//@[structural2024] edition: 2024
+//@[classic2024] run-pass
+//@[structural2024] run-pass
 //! Test cases for well-typed patterns in edition 2024. These are in their own file to ensure we
 //! pass both HIR typeck and MIR borrowck, as we may skip the latter if grouped with failing tests.
-#![allow(incomplete_features)]
-#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))]
-#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))]
+#![allow(incomplete_features, unused_mut)]
+#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
-    if let Some(Some(&x)) = &Some(&Some(0)) {
-        let _: u32 = x;
-    }
-    if let Some(Some(&x)) = &Some(Some(&0)) {
+    // Tests not using match ergonomics. These should always succeed with the same bindings.
+    if let Some(&Some(&mut ref x)) = Some(&Some(&mut 0)) {
         let _: &u32 = x;
     }
-    if let Some(Some(&&x)) = &Some(Some(&0)) {
-        let _: u32 = x;
+
+    // Tests for differences in how many layers of reference are eaten by reference patterns
+    if let Some(Some(&x)) = &Some(Some(&0)) {
+        #[cfg(stable2021)] let _: u32 = x;
+        #[cfg(any(classic2024, structural2024))] let _: &u32 = x;
     }
-    if let Some(&Some(x)) = &Some(Some(0)) {
-        let _: u32 = x;
+    if let Some(&Some(x)) = &mut Some(&Some(0)) {
+        // This additionally tests that `&` patterns can eat inherited `&mut` refs.
+        // This is possible on stable when the real reference being eaten is of a `&` type.
+        #[cfg(stable2021)] let _: u32 = x;
+        #[cfg(any(classic2024, structural2024))] let _: &u32 = x;
     }
-    if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+    if let Some(Some(&&x)) = &Some(Some(&0)) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| expected integer, found `&_`
         let _: u32 = x;
     }
+
+    // Tests for eating a lone inherited reference
     if let Some(Some(&x)) = &Some(&Some(0)) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| expected integer, found `&_`
         let _: u32 = x;
     }
-    if let Some(&Some(&x)) = &mut Some(&Some(0)) {
+    if let Some(&Some(x)) = &Some(Some(0)) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| expected `Option<{integer}>`, found `&_`
         let _: u32 = x;
     }
-    if let Some(&Some(x)) = &mut Some(&Some(0)) {
-        let _: &u32 = x;
-    }
-    if let Some(&Some(&mut ref x)) = Some(&Some(&mut 0)) {
-        let _: &u32 = x;
-    }
-    if let &Some(Some(x)) = &Some(&mut Some(0)) {
-        let _: &u32 = x;
+    if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| expected integer, found `&mut _`
+        let _: u32 = x;
     }
-    if let Some(&Some(&x)) = &Some(&mut Some(0)) {
+
+    // Tests for `&` patterns matching real `&mut` reference types
+    if let Some(&Some(&x)) = Some(&Some(&mut 0)) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| types differ in mutability
         let _: u32 = x;
     }
+
+    // Tests for eating only one layer and also eating a lone inherited reference
     if let Some(&Some(&x)) = &Some(&Some(0)) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| expected integer, found `&_`
         let _: u32 = x;
     }
-    if let Some(&Some(&x)) = &Some(&mut Some(0)) {
+
+    // Tests for `&` matching a lone inherited possibly-`&mut` reference
+    if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| expected `Option<&mut Option<{integer}>>`, found `&_`
         let _: u32 = x;
     }
-    if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) {
+    if let Some(&Some(x)) = &mut Some(Some(0)) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| expected `Option<{integer}>`, found `&_`
         let _: u32 = x;
     }
-    if let Some(&Some(&x)) = Some(&Some(&mut 0)) {
+
+    // Tests eating one layer, eating a lone inherited ref, and `&` eating `&mut` (realness varies)
+    if let Some(&Some(&x)) = &Some(&mut Some(0)) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| types differ in mutability
         let _: u32 = x;
     }
-    if let Some(&Some(x)) = &mut Some(Some(0)) {
+    if let Some(&Some(&x)) = &mut Some(&Some(0)) {
+        //[stable2021]~^ mismatched types
+        //[stable2021]~| expected integer, found `&_`
         let _: u32 = x;
     }
+
+    // Tests for eat-inner rulesets matching on the outer reference if matching on the inner
+    // reference causes a mutability mismatch, i.e. `Deref(EatInner, FallbackToOuter)`:
+    let [&mut x] = &mut [&0];
+    //[stable2021]~^ mismatched types
+    //[stable2021]~| types differ in mutability
+    let _: &u32 = x;
+
+    let [&mut ref x] = &mut [&0];
+    //[stable2021]~^ mismatched types
+    //[stable2021]~| types differ in mutability
+    let _: &&u32 = x;
+
+    let [&mut ref mut x] = &mut [&0];
+    //[stable2021]~^ mismatched types
+    //[stable2021]~| types differ in mutability
+    let _: &mut &u32 = x;
+
+    let [&mut mut x] = &mut [&0];
+    //[stable2021]~^ mismatched types
+    //[stable2021]~| types differ in mutability
+    let _: &u32 = x;
+
+    let [&mut &x] = &mut [&0];
+    //[stable2021]~^ mismatched types
+    //[stable2021]~| types differ in mutability
+    let _: u32 = x;
+
+    let [&mut &ref x] = &mut [&0];
+    //[stable2021]~^ mismatched types
+    //[stable2021]~| types differ in mutability
+    let _: &u32 = x;
+
+    let [&mut &(mut x)] = &mut [&0];
+    //[stable2021]~^ mismatched types
+    //[stable2021]~| types differ in mutability
+    let _: u32 = x;
 }
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr
new file mode 100644
index 00000000000..e9c338de243
--- /dev/null
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr
@@ -0,0 +1,260 @@
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:30:23
+   |
+LL |     if let Some(Some(&&x)) = &Some(Some(&0)) {
+   |                       ^^     --------------- this expression has type `&Option<Option<&{integer}>>`
+   |                       |
+   |                       expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     if let Some(Some(&&x)) = &Some(Some(&0)) {
+LL +     if let Some(Some(&x)) = &Some(Some(&0)) {
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:37:22
+   |
+LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
+   |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(Some(x)) = &Some(&Some(0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:42:17
+   |
+LL |     if let Some(&Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&_`
+   |
+   = note:   expected enum `Option<{integer}>`
+           found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:47:22
+   |
+LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+   |                      ^^^^^^     ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/well-typed-edition-2024.rs:47:22
+   |
+LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+   |                      ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL |     if let Some(Some(x)) = &mut Some(&mut Some(0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:54:23
+   |
+LL |     if let Some(&Some(&x)) = Some(&Some(&mut 0)) {
+   |                       ^^     ------------------- this expression has type `Option<&Option<&mut {integer}>>`
+   |                       |
+   |                       types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
+   |                       ~
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:61:23
+   |
+LL |     if let Some(&Some(&x)) = &Some(&Some(0)) {
+   |                       ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                       |
+   |                       expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(&Some(x)) = &Some(&Some(0)) {
+   |                       ~
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:68:17
+   |
+LL |     if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) {
+   |                 ^^^^^^^^^^^^^^^    ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
+   |                 |
+   |                 expected `Option<&mut Option<{integer}>>`, found `&_`
+   |
+   = note:   expected enum `Option<&mut Option<{integer}>>`
+           found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:73:17
+   |
+LL |     if let Some(&Some(x)) = &mut Some(Some(0)) {
+   |                 ^^^^^^^^    ------------------ this expression has type `&mut Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&_`
+   |
+   = note:   expected enum `Option<{integer}>`
+           found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:80:17
+   |
+LL |     if let Some(&Some(&x)) = &Some(&mut Some(0)) {
+   |                 ^^^^^^^^^    ------------------- this expression has type `&Option<&mut Option<{integer}>>`
+   |                 |
+   |                 types differ in mutability
+   |
+   = note: expected mutable reference `&mut Option<{integer}>`
+                      found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:85:23
+   |
+LL |     if let Some(&Some(&x)) = &mut Some(&Some(0)) {
+   |                       ^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
+   |                       |
+   |                       expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(&Some(x)) = &mut Some(&Some(0)) {
+   |                       ~
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:93:10
+   |
+LL |     let [&mut x] = &mut [&0];
+   |          ^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/well-typed-edition-2024.rs:93:10
+   |
+LL |     let [&mut x] = &mut [&0];
+   |          ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -     let [&mut x] = &mut [&0];
+LL +     let [x] = &mut [&0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:98:10
+   |
+LL |     let [&mut ref x] = &mut [&0];
+   |          ^^^^^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/well-typed-edition-2024.rs:98:10
+   |
+LL |     let [&mut ref x] = &mut [&0];
+   |          ^^^^^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -     let [&mut ref x] = &mut [&0];
+LL +     let [ref x] = &mut [&0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:103:10
+   |
+LL |     let [&mut ref mut x] = &mut [&0];
+   |          ^^^^^^^^^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/well-typed-edition-2024.rs:103:10
+   |
+LL |     let [&mut ref mut x] = &mut [&0];
+   |          ^^^^^^^^^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -     let [&mut ref mut x] = &mut [&0];
+LL +     let [ref mut x] = &mut [&0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:108:10
+   |
+LL |     let [&mut mut x] = &mut [&0];
+   |          ^^^^^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/well-typed-edition-2024.rs:108:10
+   |
+LL |     let [&mut mut x] = &mut [&0];
+   |          ^^^^^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL -     let [&mut mut x] = &mut [&0];
+LL +     let [mut x] = &mut [&0];
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:113:10
+   |
+LL |     let [&mut &x] = &mut [&0];
+   |          ^^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:118:10
+   |
+LL |     let [&mut &ref x] = &mut [&0];
+   |          ^^^^^^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/well-typed-edition-2024.rs:123:10
+   |
+LL |     let [&mut &(mut x)] = &mut [&0];
+   |          ^^^^^^^^^^^^^    --------- this expression has type `&mut [&{integer}; 1]`
+   |          |
+   |          types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+
+error: aborting due to 17 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/privacy/sysroot-private.default.stderr b/tests/ui/privacy/sysroot-private.default.stderr
index 845d4558d13..fef88d107e6 100644
--- a/tests/ui/privacy/sysroot-private.default.stderr
+++ b/tests/ui/privacy/sysroot-private.default.stderr
@@ -1,11 +1,11 @@
 error[E0405]: cannot find trait `Equivalent` in this scope
-  --> $DIR/sysroot-private.rs:26:18
+  --> $DIR/sysroot-private.rs:27:18
    |
 LL | trait Trait2<K>: Equivalent<K> {}
    |                  ^^^^^^^^^^ not found in this scope
 
 error[E0412]: cannot find type `K` in this scope
-  --> $DIR/sysroot-private.rs:31:35
+  --> $DIR/sysroot-private.rs:32:35
    |
 LL | fn trait_member<T>(val: &T, key: &K) -> bool {
    |                 -                 ^
@@ -22,13 +22,13 @@ LL | fn trait_member<T, K>(val: &T, key: &K) -> bool {
    |                  +++
 
 error[E0220]: associated type `ExpressionStack` not found for `Trait`
-  --> $DIR/sysroot-private.rs:21:31
+  --> $DIR/sysroot-private.rs:22:31
    |
 LL | type AssociatedTy = dyn Trait<ExpressionStack = i32, Bar = i32>;
    |                               ^^^^^^^^^^^^^^^ help: `Trait` has the following associated type: `Bar`
 
 error[E0425]: cannot find function `memchr2` in this scope
-  --> $DIR/sysroot-private.rs:39:5
+  --> $DIR/sysroot-private.rs:40:5
    |
 LL |     memchr2(b'a', b'b', buf)
    |     ^^^^^^^ not found in this scope
diff --git a/tests/ui/privacy/sysroot-private.rs b/tests/ui/privacy/sysroot-private.rs
index 67ab67c7f5c..86818574592 100644
--- a/tests/ui/privacy/sysroot-private.rs
+++ b/tests/ui/privacy/sysroot-private.rs
@@ -7,6 +7,7 @@
 //! of `std`'s dependencies, but may not be robust against dependency upgrades/changes.
 
 //@ only-unix Windows sysroots seem to not expose this dependency
+//@ ignore-emscripten neither does Emscripten
 //@ revisions: default rustc_private_enabled
 
 // Enabling `rustc_private` should `std`'s dependencies accessible, so they should show up
diff --git a/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr b/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr
index 98e6922428a..4b54b59714a 100644
--- a/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr
+++ b/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr
@@ -1,11 +1,11 @@
 error[E0405]: cannot find trait `Equivalent` in this scope
-  --> $DIR/sysroot-private.rs:26:18
+  --> $DIR/sysroot-private.rs:27:18
    |
 LL | trait Trait2<K>: Equivalent<K> {}
    |                  ^^^^^^^^^^ not found in this scope
 
 error[E0412]: cannot find type `K` in this scope
-  --> $DIR/sysroot-private.rs:31:35
+  --> $DIR/sysroot-private.rs:32:35
    |
 LL | fn trait_member<T>(val: &T, key: &K) -> bool {
    |                 -                 ^
@@ -22,13 +22,13 @@ LL | fn trait_member<T, K>(val: &T, key: &K) -> bool {
    |                  +++
 
 error[E0220]: associated type `ExpressionStack` not found for `Trait`
-  --> $DIR/sysroot-private.rs:21:31
+  --> $DIR/sysroot-private.rs:22:31
    |
 LL | type AssociatedTy = dyn Trait<ExpressionStack = i32, Bar = i32>;
    |                               ^^^^^^^^^^^^^^^ there is an associated type `ExpressionStack` in the trait `gimli::read::op::EvaluationStorage`
 
 error[E0425]: cannot find function `memchr2` in this scope
-  --> $DIR/sysroot-private.rs:39:5
+  --> $DIR/sysroot-private.rs:40:5
    |
 LL |     memchr2(b'a', b'b', buf)
    |     ^^^^^^^ not found in this scope
diff --git a/tests/ui/recursion/recursion.rs b/tests/ui/recursion/recursion.rs
index f3c633983b1..ce56fe974b7 100644
--- a/tests/ui/recursion/recursion.rs
+++ b/tests/ui/recursion/recursion.rs
@@ -1,6 +1,7 @@
 //@ build-fail
 //@ compile-flags:-C overflow-checks=off
-//@ normalize-stderr: ".nll/" -> "/"
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'"
 
 enum Nil {NilValue}
 struct Cons<T> {head:isize, tail:T}
diff --git a/tests/ui/recursion/recursion.stderr b/tests/ui/recursion/recursion.stderr
index 7a9f04d4bd6..cb9f67ba741 100644
--- a/tests/ui/recursion/recursion.stderr
+++ b/tests/ui/recursion/recursion.stderr
@@ -1,15 +1,15 @@
 error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<...>>>>>>`
-  --> $DIR/recursion.rs:18:11
+  --> $DIR/recursion.rs:19:11
    |
 LL |     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `test` defined here
-  --> $DIR/recursion.rs:16:1
+  --> $DIR/recursion.rs:17:1
    |
 LL | fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/recursion/recursion.long-type.txt'
+   = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt'
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/resolve/issue-3907-2.stderr b/tests/ui/resolve/issue-3907-2.stderr
index 4ab72a42eb8..40cdfb7a302 100644
--- a/tests/ui/resolve/issue-3907-2.stderr
+++ b/tests/ui/resolve/issue-3907-2.stderr
@@ -5,7 +5,7 @@ LL | fn bar(_x: Foo) {}
    |            ^^^ `issue_3907::Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/auxiliary/issue-3907.rs:2:8
    |
 LL |     fn bar();
diff --git a/tests/ui/asan-odr-win/asan_odr_windows.rs b/tests/ui/sanitizer/asan_odr_windows.rs
index c618ac02a66..c618ac02a66 100644
--- a/tests/ui/asan-odr-win/asan_odr_windows.rs
+++ b/tests/ui/sanitizer/asan_odr_windows.rs
diff --git a/tests/ui/asan-odr-win/auxiliary/asan_odr_win-2.rs b/tests/ui/sanitizer/auxiliary/asan_odr_win-2.rs
index 75488a29e5e..75488a29e5e 100644
--- a/tests/ui/asan-odr-win/auxiliary/asan_odr_win-2.rs
+++ b/tests/ui/sanitizer/auxiliary/asan_odr_win-2.rs
diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr
index 3e018995ba5..8382b4867e2 100644
--- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr
+++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr
@@ -8,7 +8,7 @@ LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
    |                                ^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18
    |
 LL | trait Foo {
@@ -27,7 +27,7 @@ LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
    |             ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18
    |
 LL | trait Foo {
diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr
index 12c93d58537..d324f4641cf 100644
--- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr
@@ -8,7 +8,7 @@ LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
    |             ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18
    |
 LL | trait Foo {
diff --git a/tests/ui/stability-attribute/allowed-through-unstable.rs b/tests/ui/stability-attribute/allowed-through-unstable.rs
index e03417a4dae..5baa0fda940 100644
--- a/tests/ui/stability-attribute/allowed-through-unstable.rs
+++ b/tests/ui/stability-attribute/allowed-through-unstable.rs
@@ -5,6 +5,5 @@
 
 extern crate allowed_through_unstable_core;
 
-use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable;
-use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstableWithDeprecation; //~WARN use of deprecated module `allowed_through_unstable_core::unstable_module`: use the new path instead
+use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable; //~WARN use of deprecated module `allowed_through_unstable_core::unstable_module`: use the new path instead
 use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable; //~ ERROR use of unstable library feature `unstable_test_feature`
diff --git a/tests/ui/stability-attribute/allowed-through-unstable.stderr b/tests/ui/stability-attribute/allowed-through-unstable.stderr
index 8d07b0cf9e8..bda68045002 100644
--- a/tests/ui/stability-attribute/allowed-through-unstable.stderr
+++ b/tests/ui/stability-attribute/allowed-through-unstable.stderr
@@ -1,13 +1,13 @@
 warning: use of deprecated module `allowed_through_unstable_core::unstable_module`: use the new path instead
-  --> $DIR/allowed-through-unstable.rs:9:53
+  --> $DIR/allowed-through-unstable.rs:8:53
    |
-LL | use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstableWithDeprecation;
-   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable;
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(deprecated)]` on by default
 
 error[E0658]: use of unstable library feature `unstable_test_feature`
-  --> $DIR/allowed-through-unstable.rs:10:5
+  --> $DIR/allowed-through-unstable.rs:9:5
    |
 LL | use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs b/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs
index 9dfbb451d04..23c722d6e8e 100644
--- a/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs
+++ b/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs
@@ -6,12 +6,8 @@
 #[unstable(feature = "unstable_test_feature", issue = "1")]
 pub mod unstable_module {
     #[stable(feature = "stable_test_feature", since = "1.2.0")]
-    #[rustc_allowed_through_unstable_modules]
-    pub trait OldStableTraitAllowedThoughUnstable {}
-
-    #[stable(feature = "stable_test_feature", since = "1.2.0")]
     #[rustc_allowed_through_unstable_modules = "use the new path instead"]
-    pub trait OldStableTraitAllowedThoughUnstableWithDeprecation {}
+    pub trait OldStableTraitAllowedThoughUnstable {}
 
     #[stable(feature = "stable_test_feature", since = "1.2.0")]
     pub trait NewStableTraitNotAllowedThroughUnstable {}
diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
index 08c744979f5..28427161e87 100644
--- a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
+++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
@@ -5,7 +5,7 @@ LL |     pub desc: &'static dyn Qux,
    |                        ^^^^^^^ `Qux` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8
    |
 LL | trait Qux {
@@ -44,7 +44,7 @@ LL | static FOO: &Lint = &Lint { desc: "desc" };
    |                                   ^^^^^^ `Qux` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8
    |
 LL | trait Qux {
@@ -68,7 +68,7 @@ LL | static FOO: &Lint = &Lint { desc: "desc" };
    |                                   ^^^^^^ `Qux` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8
    |
 LL | trait Qux {
diff --git a/tests/ui/suggestions/box-future-wrong-output.stderr b/tests/ui/suggestions/box-future-wrong-output.stderr
index 6a232c3444d..bac26ae8fb5 100644
--- a/tests/ui/suggestions/box-future-wrong-output.stderr
+++ b/tests/ui/suggestions/box-future-wrong-output.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/box-future-wrong-output.rs:20:39
    |
 LL |     let _: BoxFuture<'static, bool> = async {}.boxed();
-   |            ------------------------   ^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |            ------------------------   ^^^^^^^^^^^^^^^^ expected `Pin<Box<...>>`, found `Pin<Box<dyn Future<Output = ()> + Send>>`
    |            |
    |            expected due to this
    |
diff --git a/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.rs b/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.rs
index 47a590668dd..e03c43d15ee 100644
--- a/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.rs
+++ b/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.rs
@@ -7,6 +7,6 @@ fn bar<X>(x: Box<dyn FnOnce() -> X>) {}
 
 fn main() {
     foo(async move || {});
-    //~^ ERROR expected `{async closure@dont-suggest-boxing-async-closure-body.rs:9:9}` to be a closure that returns `Box<_>`
+    //~^ ERROR expected `{async closure@dont-suggest-boxing-async-closure-body.rs:9:9}` to return `Box<_>`
     bar(async move || {}); //~ ERROR mismatched types
 }
diff --git a/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.stderr b/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.stderr
index db2a3b9a9c1..abf8e2d824b 100644
--- a/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.stderr
+++ b/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.stderr
@@ -1,4 +1,4 @@
-error[E0271]: expected `{async closure@dont-suggest-boxing-async-closure-body.rs:9:9}` to be a closure that returns `Box<_>`, but it returns `{async closure body@$DIR/dont-suggest-boxing-async-closure-body.rs:9:23: 9:25}`
+error[E0271]: expected `{async closure@dont-suggest-boxing-async-closure-body.rs:9:9}` to return `Box<_>`, but it returns `{async closure body@$DIR/dont-suggest-boxing-async-closure-body.rs:9:23: 9:25}`
   --> $DIR/dont-suggest-boxing-async-closure-body.rs:9:9
    |
 LL |     foo(async move || {});
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr
index cb0e7fce910..ae009d26029 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr
@@ -5,7 +5,7 @@ LL | fn bar(x: &dyn Trait) {}
    |            ^^^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-references-self.rs:2:22
    |
 LL | trait Trait {
@@ -25,7 +25,7 @@ LL | fn foo(x: &dyn Other) {}
    |            ^^^^^^^^^ `Other` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-references-self.rs:11:14
    |
 LL | trait Other: Sized {}
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr
index 2efcad1e7bd..742011ad0c0 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr
@@ -18,7 +18,7 @@ LL |     fn f(a: dyn A) -> dyn A;
    |             ^^^^^ `A` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:3:10
    |
 LL | trait A: Sized {
@@ -46,7 +46,7 @@ LL |     fn f(a: dyn B) -> dyn B;
    |             ^^^^^ `B` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:8
    |
 LL | trait B {
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr
index ecb3ee9185f..843c139851d 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr
@@ -18,7 +18,7 @@ LL |     fn f(a: A) -> A;
    |             ^ `A` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:10
    |
 LL | trait A: Sized {
@@ -46,7 +46,7 @@ LL |     fn f(a: B) -> B;
    |             ^ `B` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:8
    |
 LL | trait B {
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr
index 696840d3ba4..e2250807603 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr
@@ -5,7 +5,7 @@ LL | fn bar(x: &dyn Trait) {}
    |            ^^^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/dyn-incompatible-trait-should-use-where-sized.rs:5:8
    |
 LL | trait Trait {
diff --git a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
index 42bc094859a..61a1d30d31d 100644
--- a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
+++ b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
@@ -32,7 +32,7 @@ error[E0308]: mismatched types
 LL | fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
    |        - found this type parameter
 LL |     Pin::new(x)
-   |     -------- ^ expected `Box<dyn Future<Output = ...> + Send>`, found type parameter `F`
+   |     -------- ^ expected `Box<dyn Future<Output = i32> + Send>`, found type parameter `F`
    |     |
    |     arguments to this function are incorrect
    |     help: use `Box::pin` to pin and box this expression: `Box::pin`
diff --git a/tests/ui/suggestions/issue-107860.stderr b/tests/ui/suggestions/issue-107860.stderr
index 4be495da46b..2bfd2193981 100644
--- a/tests/ui/suggestions/issue-107860.stderr
+++ b/tests/ui/suggestions/issue-107860.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-107860.rs:3:36
    |
 LL | async fn str<T>(T: &str) -> &str { &str }
-   |                                    ^^^^ expected `&str`, found `&fn(&str) -> ... {str::<...>}`
+   |                                    ^^^^ expected `&str`, found `&fn(&str) -> ... {str::<_>}`
    |
    = note: expected reference `&str`
               found reference `&for<'a> fn(&'a str) -> impl Future<Output = &'a str> {str::<_>}`
diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr
index 508c3ec5e4f..e7b8cd2f101 100644
--- a/tests/ui/suggestions/issue-116434-2015.stderr
+++ b/tests/ui/suggestions/issue-116434-2015.stderr
@@ -47,7 +47,7 @@ LL |     fn foo() -> Clone;
    |
    = note: the trait is not dyn compatible because it requires `Self: Sized`
    = note: for a trait to be dyn compatible it needs to allow building a vtable
-           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
 help: there is an associated type with the same name
    |
 LL |     fn foo() -> Self::Clone;
@@ -74,7 +74,7 @@ LL |     fn handle() -> DbHandle;
    |                    ^^^^^^^^ `DbHandle` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-116434-2015.rs:14:17
    |
 LL | trait DbHandle: Sized {}
diff --git a/tests/ui/suggestions/issue-98500.stderr b/tests/ui/suggestions/issue-98500.stderr
index 97b712acfcb..ec984c0d60e 100644
--- a/tests/ui/suggestions/issue-98500.stderr
+++ b/tests/ui/suggestions/issue-98500.stderr
@@ -5,7 +5,7 @@ LL | struct S(Box<dyn B>);
    |              ^^^^^ `B` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/auxiliary/dyn-incompatible.rs:4:8
    |
 LL |     fn f();
diff --git a/tests/ui/suggestions/suggest-ref-mut.rs b/tests/ui/suggestions/suggest-ref-mut.rs
index b40439b8e37..9f5df9303c3 100644
--- a/tests/ui/suggestions/suggest-ref-mut.rs
+++ b/tests/ui/suggestions/suggest-ref-mut.rs
@@ -3,7 +3,7 @@ struct X(usize);
 impl X {
     fn zap(&self) {
         //~^ HELP
-        //~| SUGGESTION &mut self
+        //~| SUGGESTION mut
         self.0 = 32;
         //~^ ERROR
     }
diff --git a/tests/ui/suggestions/suggest-ref-mut.stderr b/tests/ui/suggestions/suggest-ref-mut.stderr
index cc00022ab8e..935a04c052a 100644
--- a/tests/ui/suggestions/suggest-ref-mut.stderr
+++ b/tests/ui/suggestions/suggest-ref-mut.stderr
@@ -7,7 +7,7 @@ LL |         self.0 = 32;
 help: consider changing this to be a mutable reference
    |
 LL |     fn zap(&mut self) {
-   |            ~~~~~~~~~
+   |             +++
 
 error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
   --> $DIR/suggest-ref-mut.rs:15:5
diff --git a/tests/ui/target_modifiers/auxiliary/default_reg_struct_return.rs b/tests/ui/target_modifiers/auxiliary/default_reg_struct_return.rs
new file mode 100644
index 00000000000..355e7c56e94
--- /dev/null
+++ b/tests/ui/target_modifiers/auxiliary/default_reg_struct_return.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
+// Auxiliary build problems with aarch64-apple:
+// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
+// Auxiliary build problems with i686-mingw: linker `cc` not found
+//@ only-x86
+//@ ignore-windows
+//@ ignore-apple
+//@ needs-llvm-components: x86
+#![crate_type = "rlib"]
+#![no_core]
+#![feature(no_core, lang_items, repr_simd)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub fn somefun() {}
+
+pub struct S;
diff --git a/tests/ui/target_modifiers/auxiliary/wrong_regparm.rs b/tests/ui/target_modifiers/auxiliary/wrong_regparm.rs
new file mode 100644
index 00000000000..2e16f1ee747
--- /dev/null
+++ b/tests/ui/target_modifiers/auxiliary/wrong_regparm.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Cpanic=abort
+// Auxiliary build problems with aarch64-apple:
+// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
+// Auxiliary build problems with i686-mingw: linker `cc` not found
+//@ only-x86
+//@ ignore-windows
+//@ ignore-apple
+//@ needs-llvm-components: x86
+#![crate_type = "rlib"]
+#![no_core]
+#![feature(no_core, lang_items, repr_simd)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub fn somefun() {}
+
+pub struct S;
diff --git a/tests/ui/target_modifiers/auxiliary/wrong_regparm_and_ret.rs b/tests/ui/target_modifiers/auxiliary/wrong_regparm_and_ret.rs
new file mode 100644
index 00000000000..39c6be9d589
--- /dev/null
+++ b/tests/ui/target_modifiers/auxiliary/wrong_regparm_and_ret.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Zreg-struct-return=true -Cpanic=abort
+// Auxiliary build problems with aarch64-apple:
+// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
+// Auxiliary build problems with i686-mingw: linker `cc` not found
+//@ only-x86
+//@ ignore-windows
+//@ ignore-apple
+//@ needs-llvm-components: x86
+#![crate_type = "rlib"]
+#![no_core]
+#![feature(no_core, lang_items, repr_simd)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub fn somefun() {}
+
+pub struct S;
diff --git a/tests/ui/target_modifiers/defaults_check.error.stderr b/tests/ui/target_modifiers/defaults_check.error.stderr
new file mode 100644
index 00000000000..c545dd71069
--- /dev/null
+++ b/tests/ui/target_modifiers/defaults_check.error.stderr
@@ -0,0 +1,13 @@
+error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `defaults_check`
+  --> $DIR/defaults_check.rs:20:1
+   |
+LL | #![crate_type = "rlib"]
+   | ^
+   |
+   = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+   = note: `-Zreg-struct-return=true` in this crate is incompatible with `-Zreg-struct-return=` in dependency `default_reg_struct_return`
+   = help: set `-Zreg-struct-return=` in this crate or `-Zreg-struct-return=true` in `default_reg_struct_return`
+   = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/target_modifiers/defaults_check.rs b/tests/ui/target_modifiers/defaults_check.rs
new file mode 100644
index 00000000000..b8f4848d3a4
--- /dev/null
+++ b/tests/ui/target_modifiers/defaults_check.rs
@@ -0,0 +1,27 @@
+// Tests that default unspecified target modifier value in dependency crate is ok linked
+// with the same value, explicitly specified
+//@ aux-crate:default_reg_struct_return=default_reg_struct_return.rs
+//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
+//@ revisions:error ok ok_explicit
+//@[ok] compile-flags:
+//@[ok_explicit] compile-flags: -Zreg-struct-return=false
+//@[error] compile-flags: -Zreg-struct-return=true
+
+// Auxiliary build problems with aarch64-apple:
+// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
+// Auxiliary build problems with i686-mingw: linker `cc` not found
+//@ only-x86
+//@ ignore-windows
+//@ ignore-apple
+//@ needs-llvm-components: x86
+//@[ok] build-pass
+//@[ok_explicit] build-pass
+
+#![crate_type = "rlib"]
+//[error]~^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `defaults_check`
+#![no_core]
+#![feature(no_core, lang_items, repr_simd)]
+
+fn foo() {
+    default_reg_struct_return::somefun();
+}
diff --git a/tests/ui/target_modifiers/incompatible_regparm.allow_no_value.stderr b/tests/ui/target_modifiers/incompatible_regparm.allow_no_value.stderr
new file mode 100644
index 00000000000..8597332825b
--- /dev/null
+++ b/tests/ui/target_modifiers/incompatible_regparm.allow_no_value.stderr
@@ -0,0 +1,2 @@
+error: codegen option `unsafe-allow-abi-mismatch` requires a comma-separated list of strings (C unsafe-allow-abi-mismatch=<value>)
+
diff --git a/tests/ui/target_modifiers/incompatible_regparm.error_generated.stderr b/tests/ui/target_modifiers/incompatible_regparm.error_generated.stderr
new file mode 100644
index 00000000000..692fc7a4e3f
--- /dev/null
+++ b/tests/ui/target_modifiers/incompatible_regparm.error_generated.stderr
@@ -0,0 +1,13 @@
+error: mixing `-Zregparm` will cause an ABI mismatch in crate `incompatible_regparm`
+  --> $DIR/incompatible_regparm.rs:16:1
+   |
+LL | #![crate_type = "rlib"]
+   | ^
+   |
+   = help: the `-Zregparm` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+   = note: `-Zregparm=1` in this crate is incompatible with `-Zregparm=2` in dependency `wrong_regparm`
+   = help: set `-Zregparm=2` in this crate or `-Zregparm=1` in `wrong_regparm`
+   = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=regparm` to silence this error
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/target_modifiers/incompatible_regparm.rs b/tests/ui/target_modifiers/incompatible_regparm.rs
new file mode 100644
index 00000000000..e866c5aa891
--- /dev/null
+++ b/tests/ui/target_modifiers/incompatible_regparm.rs
@@ -0,0 +1,23 @@
+//@ aux-crate:wrong_regparm=wrong_regparm.rs
+//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=1 -Cpanic=abort
+// Auxiliary build problems with aarch64-apple:
+// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
+// Auxiliary build problems with i686-mingw: linker `cc` not found
+//@ only-x86
+//@ ignore-windows
+//@ ignore-apple
+//@ needs-llvm-components: x86
+//@ revisions:error_generated allow_regparm_mismatch allow_no_value
+
+//@[allow_regparm_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=regparm
+//@[allow_regparm_mismatch] build-pass
+//@[allow_no_value] compile-flags: -Cunsafe-allow-abi-mismatch
+
+#![crate_type = "rlib"]
+//[error_generated]~^ ERROR mixing `-Zregparm` will cause an ABI mismatch in crate `incompatible_regparm`
+#![no_core]
+#![feature(no_core, lang_items, repr_simd)]
+
+fn foo() {
+    wrong_regparm::somefun();
+}
diff --git a/tests/ui/target_modifiers/two_flags.rs b/tests/ui/target_modifiers/two_flags.rs
new file mode 100644
index 00000000000..ca17117a267
--- /dev/null
+++ b/tests/ui/target_modifiers/two_flags.rs
@@ -0,0 +1,23 @@
+//@ aux-crate:wrong_regparm_and_ret=wrong_regparm_and_ret.rs
+//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
+// Auxiliary build problems with aarch64-apple:
+// Shared library linking cc seems to convert "-m32" flag into -arch armv4t
+// Auxiliary build problems with i686-mingw: linker `cc` not found
+//@ only-x86
+//@ ignore-windows
+//@ ignore-apple
+//@ needs-llvm-components: x86
+//@ revisions:two_allowed unknown_allowed
+
+//@[two_allowed] compile-flags: -Cunsafe-allow-abi-mismatch=regparm,reg-struct-return
+//@[two_allowed] build-pass
+//@[unknown_allowed] compile-flags: -Cunsafe-allow-abi-mismatch=unknown_flag -Zregparm=2 -Zreg-struct-return=true
+
+#![crate_type = "rlib"]
+//[unknown_allowed]~^ ERROR unknown target modifier `unknown_flag`, requested by `-Cunsafe-allow-abi-mismatch=unknown_flag`
+#![no_core]
+#![feature(no_core, lang_items, repr_simd)]
+
+fn foo() {
+    wrong_regparm_and_ret::somefun();
+}
diff --git a/tests/ui/target_modifiers/two_flags.unknown_allowed.stderr b/tests/ui/target_modifiers/two_flags.unknown_allowed.stderr
new file mode 100644
index 00000000000..c8040c6e389
--- /dev/null
+++ b/tests/ui/target_modifiers/two_flags.unknown_allowed.stderr
@@ -0,0 +1,8 @@
+error: unknown target modifier `unknown_flag`, requested by `-Cunsafe-allow-abi-mismatch=unknown_flag`
+  --> $DIR/two_flags.rs:16:1
+   |
+LL | #![crate_type = "rlib"]
+   | ^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 916f296ccfc..910582ae4d9 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -26,16 +26,16 @@ params: [
 body:
     Expr {
         ty: bool
-        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
         span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
         kind: 
             Scope {
-                region_scope: Node(26)
-                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).26))
+                region_scope: Node(28)
+                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).28))
                 value:
                     Expr {
                         ty: bool
-                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                         span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
                         kind: 
                             Block {
@@ -47,7 +47,7 @@ body:
                                 expr:
                                     Expr {
                                         ty: bool
-                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                                         span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
                                         kind: 
                                             Scope {
@@ -56,14 +56,14 @@ body:
                                                 value:
                                                     Expr {
                                                         ty: bool
-                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                                                         span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
                                                         kind: 
                                                             Match {
                                                                 scrutinee:
                                                                     Expr {
                                                                         ty: Foo
-                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                         kind: 
                                                                             Scope {
@@ -72,7 +72,7 @@ body:
                                                                                 value:
                                                                                     Expr {
                                                                                         ty: Foo
-                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                         kind: 
                                                                                             VarRef {
@@ -123,16 +123,16 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(14)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                 kind: 
                                                                                     Scope {
-                                                                                        region_scope: Node(14)
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14))
+                                                                                        region_scope: Node(15)
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).15))
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(14)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
@@ -140,8 +140,8 @@ body:
                                                                                             }
                                                                                     }
                                                                             }
-                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13))
-                                                                        scope: Node(13)
+                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14))
+                                                                        scope: Node(14)
                                                                         span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0)
                                                                     }
                                                                     Arm {
@@ -175,16 +175,16 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(20)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                 kind: 
                                                                                     Scope {
-                                                                                        region_scope: Node(20)
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20))
+                                                                                        region_scope: Node(21)
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).21))
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(20)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
@@ -192,8 +192,8 @@ body:
                                                                                             }
                                                                                     }
                                                                             }
-                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19))
-                                                                        scope: Node(19)
+                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20))
+                                                                        scope: Node(20)
                                                                         span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0)
                                                                     }
                                                                     Arm {
@@ -219,16 +219,16 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                 kind: 
                                                                                     Scope {
-                                                                                        region_scope: Node(25)
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).25))
+                                                                                        region_scope: Node(27)
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).27))
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
@@ -236,8 +236,8 @@ body:
                                                                                             }
                                                                                     }
                                                                             }
-                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24))
-                                                                        scope: Node(24)
+                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).26))
+                                                                        scope: Node(26)
                                                                         span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0)
                                                                     }
                                                                 ]
diff --git a/tests/ui/traits/alias/generic-default-in-dyn.stderr b/tests/ui/traits/alias/generic-default-in-dyn.stderr
index 1ab9e6d5c5c..c6f8ab4137b 100644
--- a/tests/ui/traits/alias/generic-default-in-dyn.stderr
+++ b/tests/ui/traits/alias/generic-default-in-dyn.stderr
@@ -15,7 +15,7 @@ LL | struct Foo<T>(dyn SendEqAlias<T>);
    |                   ^^^^^^^^^^^^^^ `SendEqAlias` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/generic-default-in-dyn.rs:1:24
    |
 LL | trait SendEqAlias<T> = PartialEq;
@@ -30,7 +30,7 @@ LL | struct Bar<T>(dyn SendEqAlias<T>, T);
    |                   ^^^^^^^^^^^^^^ `SendEqAlias` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/generic-default-in-dyn.rs:1:24
    |
 LL | trait SendEqAlias<T> = PartialEq;
diff --git a/tests/ui/traits/alias/object-fail.stderr b/tests/ui/traits/alias/object-fail.stderr
index 52ce79a4597..d60d8843407 100644
--- a/tests/ui/traits/alias/object-fail.stderr
+++ b/tests/ui/traits/alias/object-fail.stderr
@@ -5,7 +5,7 @@ LL |     let _: &dyn EqAlias = &123;
    |                 ^^^^^^^ `EqAlias` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $SRC_DIR/core/src/cmp.rs:LL:COL
    |
    = note: ...because it uses `Self` as a type parameter
diff --git a/tests/ui/traits/alias/self-in-const-generics.stderr b/tests/ui/traits/alias/self-in-const-generics.stderr
index 3c799492591..b5538cb6e2f 100644
--- a/tests/ui/traits/alias/self-in-const-generics.stderr
+++ b/tests/ui/traits/alias/self-in-const-generics.stderr
@@ -5,7 +5,7 @@ LL | fn foo(x: &dyn BB) {}
    |                ^^ `BB` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/self-in-const-generics.rs:7:12
    |
 LL | trait BB = Bar<{ 2 + 1 }>;
diff --git a/tests/ui/traits/alias/self-in-generics.stderr b/tests/ui/traits/alias/self-in-generics.stderr
index 5639b2b44a1..afe4dff45ed 100644
--- a/tests/ui/traits/alias/self-in-generics.stderr
+++ b/tests/ui/traits/alias/self-in-generics.stderr
@@ -5,7 +5,7 @@ LL | pub fn f(_f: &dyn SelfInput) {}
    |                   ^^^^^^^^^ `SelfInput` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/self-in-generics.rs:6:23
    |
 LL | pub trait SelfInput = Fn(&mut Self);
diff --git a/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs b/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs
new file mode 100644
index 00000000000..d5240b7e18d
--- /dev/null
+++ b/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs
@@ -0,0 +1,28 @@
+//@ check-pass
+
+#![feature(const_deref)]
+#![feature(const_trait_impl)]
+
+use std::ops::Deref;
+
+struct Wrap<T>(T);
+struct Foo;
+
+impl Foo {
+    const fn call(&self) {}
+}
+
+impl<T> const Deref for Wrap<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+const fn foo() {
+    let x = Wrap(Foo);
+    x.call();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr
index 8bfda71bac1..5299236026d 100644
--- a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr
+++ b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr
@@ -2,7 +2,7 @@ error[E0271]: type mismatch resolving `<dyn Pointee<Metadata = ()> as Pointee>::
   --> $DIR/ice-with-dyn-pointee-errors.rs:9:33
    |
 LL |     unknown_sized_object_ptr_in(x)
-   |     --------------------------- ^ expected `()`, found `DynMetadata<dyn Pointee<Metadata = ...>>`
+   |     --------------------------- ^ expected `()`, found `DynMetadata<dyn Pointee<Metadata = ()>>`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/traits/issue-20692.stderr b/tests/ui/traits/issue-20692.stderr
index 50ea7cde961..32e29de49a1 100644
--- a/tests/ui/traits/issue-20692.stderr
+++ b/tests/ui/traits/issue-20692.stderr
@@ -5,7 +5,7 @@ LL |     &dyn Array;
    |     ^^^^^^^^^^ `Array` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-20692.rs:1:14
    |
 LL | trait Array: Sized + Copy {}
@@ -21,7 +21,7 @@ LL |     let _ = x
    |             ^ `Array` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-20692.rs:1:14
    |
 LL | trait Array: Sized + Copy {}
diff --git a/tests/ui/traits/issue-28576.stderr b/tests/ui/traits/issue-28576.stderr
index ba113d573d6..ba61ce98554 100644
--- a/tests/ui/traits/issue-28576.stderr
+++ b/tests/ui/traits/issue-28576.stderr
@@ -27,7 +27,7 @@ LL | |               <Assoc=()>
    | |________________________^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-28576.rs:5:16
    |
 LL | pub trait Bar: Foo<Assoc=()> {
diff --git a/tests/ui/traits/issue-38404.stderr b/tests/ui/traits/issue-38404.stderr
index f9e592255dd..63269d3379e 100644
--- a/tests/ui/traits/issue-38404.stderr
+++ b/tests/ui/traits/issue-38404.stderr
@@ -5,7 +5,7 @@ LL | trait C<T>: A<dyn B<T, Output = usize>> {}
    |                   ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-38404.rs:1:13
    |
 LL | trait A<T>: std::ops::Add<Self> + Sized {}
@@ -20,7 +20,7 @@ LL | trait C<T>: A<dyn B<T, Output = usize>> {}
    |                   ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-38404.rs:1:13
    |
 LL | trait A<T>: std::ops::Add<Self> + Sized {}
@@ -36,7 +36,7 @@ LL | trait C<T>: A<dyn B<T, Output = usize>> {}
    |                   ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-38404.rs:1:13
    |
 LL | trait A<T>: std::ops::Add<Self> + Sized {}
diff --git a/tests/ui/traits/issue-38604.stderr b/tests/ui/traits/issue-38604.stderr
index 94f9c1540ad..e6a6b44e730 100644
--- a/tests/ui/traits/issue-38604.stderr
+++ b/tests/ui/traits/issue-38604.stderr
@@ -5,7 +5,7 @@ LL |     let _f: Box<dyn Foo> =
    |             ^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-38604.rs:2:22
    |
 LL | trait Foo where u32: Q<Self> {
@@ -21,7 +21,7 @@ LL |         Box::new(());
    |         ^^^^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-38604.rs:2:22
    |
 LL | trait Foo where u32: Q<Self> {
diff --git a/tests/ui/traits/issue-72410.stderr b/tests/ui/traits/issue-72410.stderr
index 002345bff84..c9e133437dd 100644
--- a/tests/ui/traits/issue-72410.stderr
+++ b/tests/ui/traits/issue-72410.stderr
@@ -5,7 +5,7 @@ LL |     where for<'a> &'a mut [dyn Bar]: ;
    |                   ^^^^^^^^^^^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-72410.rs:13:8
    |
 LL | pub trait Bar {
diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr
index c97158a5b76..58c558d6685 100644
--- a/tests/ui/traits/item-privacy.stderr
+++ b/tests/ui/traits/item-privacy.stderr
@@ -143,7 +143,7 @@ LL |     <dyn C>::A;
    |      ^^^^^ `assoc_const::C` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/item-privacy.rs:25:15
    |
 LL |         const A: u8 = 0;
diff --git a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
index 682d18842b8..c8a1329e3d0 100644
--- a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
+++ b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr
@@ -41,7 +41,7 @@ LL | impl Foo<i64> {
    |      ^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/missing-for-type-in-impl.rs:4:8
    |
 LL | trait Foo<T> {
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
index 377dfc8b529..425f2d59222 100644
--- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
@@ -1,8 +1,8 @@
-error[E0284]: type annotations needed: cannot normalize `X::{constant#0}`
+error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated`
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:10
    |
 LL | struct X<const FN: fn() = { || {} }>;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `X::{constant#0}`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr
index b96bfab927d..2d0c503bc95 100644
--- a/tests/ui/traits/next-solver/specialization-transmute.stderr
+++ b/tests/ui/traits/next-solver/specialization-transmute.stderr
@@ -10,11 +10,11 @@ LL | #![feature(specialization)]
 
 error: cannot normalize `<T as Default>::Id: '_`
 
-error[E0284]: type annotations needed: cannot normalize `<T as Default>::Id`
+error[E0282]: type annotations needed
   --> $DIR/specialization-transmute.rs:15:23
    |
 LL |     fn intu(&self) -> &Self::Id {
-   |                       ^^^^^^^^^ cannot normalize `<T as Default>::Id`
+   |                       ^^^^^^^^^ cannot infer type for reference `&<T as Default>::Id`
 
 error[E0284]: type annotations needed: cannot satisfy `<T as Default>::Id normalizes-to T`
   --> $DIR/specialization-transmute.rs:17:9
@@ -36,4 +36,5 @@ LL | fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
 
 error: aborting due to 4 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0282, E0284.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr
index 8448890c084..43b69d0b50e 100644
--- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr
+++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr
@@ -14,7 +14,7 @@ LL |     let x: &dyn Foo = &();
    |                       ^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/supertrait-dyn-compatibility.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
@@ -31,7 +31,7 @@ LL |     let x: &dyn Foo = &();
    |            ^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/supertrait-dyn-compatibility.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
@@ -47,7 +47,7 @@ LL |     needs_bar(x);
    |     ^^^^^^^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/supertrait-dyn-compatibility.rs:4:12
    |
 LL | trait Foo: for<T> Bar<T> {}
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs
index 2a301788525..2a301788525 100644
--- a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs
+++ b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr
index 38dcdbd0af2..38dcdbd0af2 100644
--- a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr
+++ b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.rs
index 23f3666618b..23f3666618b 100644
--- a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs
+++ b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.rs
diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.stderr
index 3c352c9889c..3c352c9889c 100644
--- a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr
+++ b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.stderr
diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
index ae3762704c6..b4bbd65b2f4 100644
--- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
+++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
@@ -20,7 +20,7 @@ LL |     let b: &dyn FromResidual = &();
    |                                ^^^ `FromResidual` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8
    |
 LL | trait FromResidual<R = <Self as Try>::Residual> {
@@ -44,7 +44,7 @@ LL |     let b: &dyn FromResidual = &();
    |            ^^^^^^^^^^^^^^^^^ `FromResidual` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8
    |
 LL | trait FromResidual<R = <Self as Try>::Residual> {
diff --git a/tests/ui/traits/object/macro-matcher.stderr b/tests/ui/traits/object/macro-matcher.stderr
index ab0fc213c9f..3c668ce99c7 100644
--- a/tests/ui/traits/object/macro-matcher.stderr
+++ b/tests/ui/traits/object/macro-matcher.stderr
@@ -12,7 +12,7 @@ LL |     m!(dyn Copy + Send + 'static);
    |
    = note: the trait is not dyn compatible because it requires `Self: Sized`
    = note: for a trait to be dyn compatible it needs to allow building a vtable
-           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr
index af941e69c5f..2f9fdf151f0 100644
--- a/tests/ui/traits/object/pretty.stderr
+++ b/tests/ui/traits/object/pretty.stderr
@@ -110,7 +110,7 @@ error[E0308]: mismatched types
   --> $DIR/pretty.rs:36:79
    |
 LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x }
-   |                                                                            -  ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>`
+   |                                                                            -  ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = &u8>`
    |                                                                            |
    |                                                                            help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>`
    |
@@ -132,7 +132,7 @@ error[E0308]: mismatched types
   --> $DIR/pretty.rs:38:73
    |
 LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x }
-   |                                                                      -  ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = ...>`
+   |                                                                      -  ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = u8>`
    |                                                                      |
    |                                                                      help: try adding a return type: `-> &dyn AnyDifferentBinders<Assoc = u8>`
    |
diff --git a/tests/ui/traits/object/print_vtable_sizes.rs b/tests/ui/traits/object/print_vtable_sizes.rs
deleted file mode 100644
index 2b1745da5f3..00000000000
--- a/tests/ui/traits/object/print_vtable_sizes.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-//@ check-pass
-//@ compile-flags: -Z print-vtable-sizes
-#![crate_type = "lib"]
-
-trait A<T: help::V>: AsRef<[T::V]> + AsMut<[T::V]> {}
-
-trait B<T>: AsRef<T> + AsRef<T> + AsRef<T> + AsRef<T> {}
-
-trait C {
-    fn x() {} // not dyn-compatible, shouldn't be reported
-}
-
-// This does not have any upcasting cost,
-// because both `Send` and `Sync` are traits
-// with no methods
-trait D: Send + Sync + help::MarkerWithSuper {}
-
-// This can't have no cost without reordering,
-// because `Super::f`.
-trait E: help::MarkerWithSuper + Send + Sync {}
-
-trait F {
-    fn a(&self);
-    fn b(&self);
-    fn c(&self);
-
-    fn d() -> Self
-    where
-        Self: Sized;
-}
-
-trait G: AsRef<u8> + AsRef<u16> + help::MarkerWithSuper {
-    fn a(&self);
-    fn b(&self);
-    fn c(&self);
-    fn d(&self);
-    fn e(&self);
-
-    fn f() -> Self
-    where
-        Self: Sized;
-}
-
-// Traits with the same name
-const _: () = {
-    trait S {}
-};
-const _: () = {
-    trait S {}
-};
-
-mod help {
-    pub trait V {
-        type V;
-    }
-
-    pub trait MarkerWithSuper: Super {}
-
-    pub trait Super {
-        fn f(&self);
-    }
-}
diff --git a/tests/ui/traits/object/print_vtable_sizes.stdout b/tests/ui/traits/object/print_vtable_sizes.stdout
deleted file mode 100644
index 4daf4769576..00000000000
--- a/tests/ui/traits/object/print_vtable_sizes.stdout
+++ /dev/null
@@ -1,11 +0,0 @@
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "A", "entries": "6", "entries_ignoring_upcasting": "5", "entries_for_upcasting": "1", "upcasting_cost_percent": "20" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "G", "entries": "13", "entries_ignoring_upcasting": "11", "entries_for_upcasting": "2", "upcasting_cost_percent": "18.181818181818183" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "B", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "D", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "E", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "F", "entries": "6", "entries_ignoring_upcasting": "6", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "help::MarkerWithSuper", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "help::Super", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
-print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "help::V", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
diff --git a/tests/ui/traits/object/safety.stderr b/tests/ui/traits/object/safety.stderr
index eab59f39c28..593e42619f4 100644
--- a/tests/ui/traits/object/safety.stderr
+++ b/tests/ui/traits/object/safety.stderr
@@ -5,7 +5,7 @@ LL |     let _: &dyn Tr = &St;
    |                      ^^^ `Tr` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/safety.rs:4:8
    |
 LL | trait Tr {
@@ -30,7 +30,7 @@ LL |     let _: &dyn Tr = &St;
    |            ^^^^^^^ `Tr` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/safety.rs:4:8
    |
 LL | trait Tr {
diff --git a/tests/ui/traits/on_unimplemented_long_types.rs b/tests/ui/traits/on_unimplemented_long_types.rs
index 98749b8db7a..c652b71e51a 100644
--- a/tests/ui/traits/on_unimplemented_long_types.rs
+++ b/tests/ui/traits/on_unimplemented_long_types.rs
@@ -1,5 +1,6 @@
 //@ compile-flags: --diagnostic-width=60 -Z write-long-types-to-disk=yes
-//@ normalize-stderr: "long-type-\d+" -> "long-type-hash"
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'"
 
 pub fn foo() -> impl std::fmt::Display {
     //~^ ERROR doesn't implement `std::fmt::Display`
diff --git a/tests/ui/traits/on_unimplemented_long_types.stderr b/tests/ui/traits/on_unimplemented_long_types.stderr
index bddc5695696..2705d7c501e 100644
--- a/tests/ui/traits/on_unimplemented_long_types.stderr
+++ b/tests/ui/traits/on_unimplemented_long_types.stderr
@@ -1,5 +1,5 @@
 error[E0277]: `Option<Option<Option<...>>>` doesn't implement `std::fmt::Display`
-  --> $DIR/on_unimplemented_long_types.rs:4:17
+  --> $DIR/on_unimplemented_long_types.rs:5:17
    |
 LL |   pub fn foo() -> impl std::fmt::Display {
    |                   ^^^^^^^^^^^^^^^^^^^^^^ `Option<Option<Option<...>>>` cannot be formatted with the default formatter
@@ -13,11 +13,9 @@ LL | |         ))))))))))),
 LL | |     )))))))))))
    | |_______________- return type was inferred to be `Option<Option<Option<...>>>` here
    |
-   = note: the full name for the type has been written to '$TEST_BUILD_DIR/traits/on_unimplemented_long_types/on_unimplemented_long_types.long-type-hash.txt'
-   = note: consider using `--verbose` to print the full type name to the console
    = help: the trait `std::fmt::Display` is not implemented for `Option<Option<Option<...>>>`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-   = note: the full name for the type has been written to '$TEST_BUILD_DIR/traits/on_unimplemented_long_types/on_unimplemented_long_types.long-type-hash.txt'
+   = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'
    = note: consider using `--verbose` to print the full type name to the console
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/traits/sized-coniductive.rs b/tests/ui/traits/sized-coniductive.rs
deleted file mode 100644
index 5f63b166f98..00000000000
--- a/tests/ui/traits/sized-coniductive.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ check-pass
-// https://github.com/rust-lang/rust/issues/129541
-
-#[derive(Clone)]
-struct Test {
-    field: std::borrow::Cow<'static, [Self]>,
-}
-
-#[derive(Clone)]
-struct Hello {
-    a: <[Hello] as std::borrow::ToOwned>::Owned,
-}
-
-fn main(){}
diff --git a/tests/ui/traits/solver-cycles/129541-recursive-struct-and-array-impl.rs b/tests/ui/traits/solver-cycles/129541-recursive-struct-and-array-impl.rs
deleted file mode 100644
index defb39aae06..00000000000
--- a/tests/ui/traits/solver-cycles/129541-recursive-struct-and-array-impl.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Regression test for #129541
-
-//@ check-pass
-
-trait Bound {}
-trait Normalize {
-    type Assoc;
-}
-
-impl<T: Bound> Normalize for T {
-    type Assoc = T;
-}
-
-impl<T: Bound> Normalize for [T] {
-    type Assoc = T;
-}
-
-impl Bound for Hello {}
-struct Hello {
-    a: <[Hello] as Normalize>::Assoc,
-}
-
-fn main() {}
diff --git a/tests/ui/traits/solver-cycles/129541-recursive-struct.rs b/tests/ui/traits/solver-cycles/129541-recursive-struct.rs
index d4339dd54d6..4fbcbefec91 100644
--- a/tests/ui/traits/solver-cycles/129541-recursive-struct.rs
+++ b/tests/ui/traits/solver-cycles/129541-recursive-struct.rs
@@ -1,5 +1,6 @@
 // Regression test for #129541
 
+//@ revisions: unique multiple
 //@ check-pass
 
 trait Bound {}
@@ -7,6 +8,10 @@ trait Normalize {
     type Assoc;
 }
 
+#[cfg(multiple)]
+impl<T: Bound> Normalize for T {
+    type Assoc = T;
+}
 impl<T: Bound> Normalize for [T] {
     type Assoc = T;
 }
diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr
index 8915e490b4d..6a6cb503aa4 100644
--- a/tests/ui/traits/test-2.stderr
+++ b/tests/ui/traits/test-2.stderr
@@ -33,7 +33,7 @@ LL |     (Box::new(10) as Box<dyn bar>).dup();
    |                      ^^^^^^^^^^^^ `bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/test-2.rs:4:30
    |
 LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
@@ -56,7 +56,7 @@ LL |     (Box::new(10) as Box<dyn bar>).dup();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/test-2.rs:4:30
    |
 LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
@@ -79,7 +79,7 @@ LL |     (Box::new(10) as Box<dyn bar>).dup();
    |      ^^^^^^^^^^^^ `bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/test-2.rs:4:30
    |
 LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.rs
new file mode 100644
index 00000000000..796ddec46ac
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.rs
@@ -0,0 +1,27 @@
+#![feature(rustc_attrs)]
+
+// Test for <https://github.com/rust-lang/rust/issues/135316>.
+
+trait Supertrait<T> {
+    fn _print_numbers(&self, mem: &[usize; 100]) {
+    }
+}
+impl<T> Supertrait<T> for () {}
+
+trait Trait<T, U>: Supertrait<T> + Supertrait<U> {
+    fn say_hello(&self, _: &usize) {
+    }
+}
+impl<T, U> Trait<T, U> for () {}
+
+// We should observe compatibility between these two vtables.
+
+#[rustc_dump_vtable]
+type First = dyn for<'a> Trait<&'static (), &'a ()>;
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
+type Second = dyn Trait<&'static (), &'static ()>;
+//~^ ERROR vtable entries
+
+fn main() {}
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.stderr b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.stderr
new file mode 100644
index 00000000000..24fa1650ca1
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.stderr
@@ -0,0 +1,26 @@
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<dyn for<'a> Trait<&(), &'a ()> as Supertrait<&()>>::_print_numbers - shim(reify)),
+           Method(<dyn for<'a> Trait<&(), &'a ()> as Trait<&(), &()>>::say_hello - shim(reify)),
+       ]
+  --> $DIR/multiple-supertraits-modulo-binder-vtable.rs:20:1
+   |
+LL | type First = dyn for<'a> Trait<&'static (), &'a ()>;
+   | ^^^^^^^^^^
+
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<dyn Trait<&(), &()> as Supertrait<&()>>::_print_numbers - shim(reify)),
+           Method(<dyn Trait<&(), &()> as Trait<&(), &()>>::say_hello - shim(reify)),
+       ]
+  --> $DIR/multiple-supertraits-modulo-binder-vtable.rs:24:1
+   |
+LL | type Second = dyn Trait<&'static (), &'static ()>;
+   | ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs
new file mode 100644
index 00000000000..510a1471af2
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs
@@ -0,0 +1,26 @@
+//@ run-pass
+//@ check-run-results
+
+// Test for <https://github.com/rust-lang/rust/issues/135316>.
+
+#![feature(trait_upcasting)]
+
+trait Supertrait<T> {
+    fn _print_numbers(&self, mem: &[usize; 100]) {
+        println!("{mem:?}");
+    }
+}
+impl<T> Supertrait<T> for () {}
+
+trait Trait<T, U>: Supertrait<T> + Supertrait<U> {
+    fn say_hello(&self, _: &usize) {
+        println!("Hello!");
+    }
+}
+impl<T, U> Trait<T, U> for () {}
+
+fn main() {
+    (&() as &'static dyn for<'a> Trait<&'static (), &'a ()>
+        as &'static dyn Trait<&'static (), &'static ()>)
+        .say_hello(&0);
+}
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout
new file mode 100644
index 00000000000..10ddd6d257e
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout
@@ -0,0 +1 @@
+Hello!
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs
new file mode 100644
index 00000000000..69a71859a5c
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs
@@ -0,0 +1,37 @@
+#![feature(rustc_attrs)]
+#![feature(trait_upcasting)]
+
+// Test for <https://github.com/rust-lang/rust/issues/135315>.
+
+trait Supertrait<T> {
+    fn _print_numbers(&self, mem: &[usize; 100]) {
+        println!("{mem:?}");
+    }
+}
+impl<T> Supertrait<T> for () {}
+
+trait Identity {
+    type Selff;
+}
+impl<Selff> Identity for Selff {
+    type Selff = Selff;
+}
+
+trait Middle<T>: Supertrait<()> + Supertrait<T> {
+    fn say_hello(&self, _: &usize) {
+        println!("Hello!");
+    }
+}
+impl<T> Middle<T> for () {}
+
+trait Trait: Middle<<() as Identity>::Selff> {}
+
+#[rustc_dump_vtable]
+impl Trait for () {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
+type Virtual = dyn Middle<()>;
+//~^ ERROR vtable entries
+
+fn main() {}
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr
new file mode 100644
index 00000000000..757e2dc6939
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr
@@ -0,0 +1,26 @@
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<() as Supertrait<()>>::_print_numbers),
+           Method(<() as Middle<()>>::say_hello),
+       ]
+  --> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:30:1
+   |
+LL | impl Trait for () {}
+   | ^^^^^^^^^^^^^^^^^
+
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<dyn Middle<()> as Supertrait<()>>::_print_numbers - shim(reify)),
+           Method(<dyn Middle<()> as Middle<()>>::say_hello - shim(reify)),
+       ]
+  --> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:34:1
+   |
+LL | type Virtual = dyn Middle<()>;
+   | ^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs
new file mode 100644
index 00000000000..c744e6e64f5
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs
@@ -0,0 +1,34 @@
+//@ run-pass
+//@ check-run-results
+
+#![feature(trait_upcasting)]
+
+// Test for <https://github.com/rust-lang/rust/issues/135315>.
+
+trait Supertrait<T> {
+    fn _print_numbers(&self, mem: &[usize; 100]) {
+        println!("{mem:?}");
+    }
+}
+impl<T> Supertrait<T> for () {}
+
+trait Identity {
+    type Selff;
+}
+impl<Selff> Identity for Selff {
+    type Selff = Selff;
+}
+
+trait Middle<T>: Supertrait<()> + Supertrait<T> {
+    fn say_hello(&self, _: &usize) {
+        println!("Hello!");
+    }
+}
+impl<T> Middle<T> for () {}
+
+trait Trait: Middle<<() as Identity>::Selff> {}
+impl Trait for () {}
+
+fn main() {
+    (&() as &dyn Trait as &dyn Middle<()>).say_hello(&0);
+}
diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.run.stdout b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.run.stdout
new file mode 100644
index 00000000000..10ddd6d257e
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.run.stdout
@@ -0,0 +1 @@
+Hello!
diff --git a/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs b/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs
new file mode 100644
index 00000000000..6cd74b6c7f7
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs
@@ -0,0 +1,30 @@
+//@ run-pass
+
+#![feature(trait_upcasting)]
+
+trait Super<U> {
+    fn call(&self)
+    where
+        U: HigherRanked,
+    {
+    }
+}
+
+impl<T> Super<T> for () {}
+
+trait HigherRanked {}
+impl HigherRanked for for<'a> fn(&'a ()) {}
+
+trait Unimplemented {}
+impl<T: Unimplemented> HigherRanked for T {}
+
+trait Sub: Super<fn(&'static ())> + Super<for<'a> fn(&'a ())> {}
+impl Sub for () {}
+
+fn main() {
+    let a: &dyn Sub = &();
+    // `Super<fn(&'static ())>` and `Super<for<'a> fn(&'a ())>` have different
+    // vtables and we need to upcast to the latter!
+    let b: &dyn Super<for<'a> fn(&'a ())> = a;
+    b.call();
+}
diff --git a/tests/ui/traits/vtable/multiple-markers.rs b/tests/ui/traits/vtable/multiple-markers.rs
index 8a9e7a006cf..8eba5135582 100644
--- a/tests/ui/traits/vtable/multiple-markers.rs
+++ b/tests/ui/traits/vtable/multiple-markers.rs
@@ -2,8 +2,7 @@
 //
 // This test makes sure that multiple marker (method-less) traits can reuse the
 // same pointer for upcasting.
-//
-//@ build-fail
+
 #![crate_type = "lib"]
 #![feature(rustc_attrs)]
 
@@ -17,17 +16,13 @@ trait T {
     fn method(&self) {}
 }
 
-#[rustc_dump_vtable]
-trait A: M0 + M1 + M2 + T {} //~ error: vtable entries for `<S as A>`:
+trait A: M0 + M1 + M2 + T {}
 
-#[rustc_dump_vtable]
-trait B: M0 + M1 + T + M2 {} //~ error: vtable entries for `<S as B>`:
+trait B: M0 + M1 + T + M2 {}
 
-#[rustc_dump_vtable]
-trait C: M0 + T + M1 + M2 {} //~ error: vtable entries for `<S as C>`:
+trait C: M0 + T + M1 + M2 {}
 
-#[rustc_dump_vtable]
-trait D: T + M0 + M1 + M2 {} //~ error: vtable entries for `<S as D>`:
+trait D: T + M0 + M1 + M2 {}
 
 struct S;
 
@@ -35,13 +30,21 @@ impl M0 for S {}
 impl M1 for S {}
 impl M2 for S {}
 impl T for S {}
+
+#[rustc_dump_vtable]
 impl A for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl B for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl C for S {}
-impl D for S {}
+//~^ ERROR vtable entries
 
-pub fn require_vtables() {
-    fn require_vtables(_: &dyn A, _: &dyn B, _: &dyn C, _: &dyn D) {}
+#[rustc_dump_vtable]
+impl D for S {}
+//~^ ERROR vtable entries
 
-    require_vtables(&S, &S, &S, &S)
-}
+fn main() {}
diff --git a/tests/ui/traits/vtable/multiple-markers.stderr b/tests/ui/traits/vtable/multiple-markers.stderr
index 36ac8b24eb5..35dd3c2516d 100644
--- a/tests/ui/traits/vtable/multiple-markers.stderr
+++ b/tests/ui/traits/vtable/multiple-markers.stderr
@@ -1,46 +1,46 @@
-error: vtable entries for `<S as A>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as T>::method),
        ]
-  --> $DIR/multiple-markers.rs:21:1
+  --> $DIR/multiple-markers.rs:35:1
    |
-LL | trait A: M0 + M1 + M2 + T {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl A for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as B>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as T>::method),
        ]
-  --> $DIR/multiple-markers.rs:24:1
+  --> $DIR/multiple-markers.rs:39:1
    |
-LL | trait B: M0 + M1 + T + M2 {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl B for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as C>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as T>::method),
        ]
-  --> $DIR/multiple-markers.rs:27:1
+  --> $DIR/multiple-markers.rs:43:1
    |
-LL | trait C: M0 + T + M1 + M2 {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl C for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as D>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as T>::method),
        ]
-  --> $DIR/multiple-markers.rs:30:1
+  --> $DIR/multiple-markers.rs:47:1
    |
-LL | trait D: T + M0 + M1 + M2 {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl D for S {}
+   | ^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/traits/vtable/vtable-diamond.rs b/tests/ui/traits/vtable/vtable-diamond.rs
index 2cfa86c526d..56053f6d026 100644
--- a/tests/ui/traits/vtable/vtable-diamond.rs
+++ b/tests/ui/traits/vtable/vtable-diamond.rs
@@ -1,44 +1,37 @@
-//@ build-fail
 #![feature(rustc_attrs)]
 
-#[rustc_dump_vtable]
 trait A {
     fn foo_a(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait B: A {
     fn foo_b(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait C: A {
-    //~^ error vtable
     fn foo_c(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait D: B + C {
-    //~^ error vtable
     fn foo_d(&self) {}
 }
 
 struct S;
 
+#[rustc_dump_vtable]
 impl A for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl B for S {}
-impl C for S {}
-impl D for S {}
+//~^ ERROR vtable entries
 
-fn foo(d: &dyn D) {
-    d.foo_d();
-}
+#[rustc_dump_vtable]
+impl C for S {}
+//~^ ERROR vtable entries
 
-fn bar(d: &dyn C) {
-    d.foo_c();
-}
+#[rustc_dump_vtable]
+impl D for S {}
+//~^ ERROR vtable entries
 
-fn main() {
-    foo(&S);
-    bar(&S);
-}
+fn main() {}
diff --git a/tests/ui/traits/vtable/vtable-diamond.stderr b/tests/ui/traits/vtable/vtable-diamond.stderr
index f3718c5d852..4644bf339b1 100644
--- a/tests/ui/traits/vtable/vtable-diamond.stderr
+++ b/tests/ui/traits/vtable/vtable-diamond.stderr
@@ -1,29 +1,52 @@
-error: vtable entries for `<S as D>`: [
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as A>::foo_a),
+       ]
+  --> $DIR/vtable-diamond.rs:22:1
+   |
+LL | impl A for S {}
+   | ^^^^^^^^^^^^
+
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as A>::foo_a),
            Method(<S as B>::foo_b),
+       ]
+  --> $DIR/vtable-diamond.rs:26:1
+   |
+LL | impl B for S {}
+   | ^^^^^^^^^^^^
+
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as A>::foo_a),
            Method(<S as C>::foo_c),
-           TraitVPtr(<S as C>),
-           Method(<S as D>::foo_d),
        ]
-  --> $DIR/vtable-diamond.rs:21:1
+  --> $DIR/vtable-diamond.rs:30:1
    |
-LL | trait D: B + C {
-   | ^^^^^^^^^^^^^^
+LL | impl C for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as C>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as A>::foo_a),
+           Method(<S as B>::foo_b),
            Method(<S as C>::foo_c),
+           TraitVPtr(<S as C>),
+           Method(<S as D>::foo_d),
        ]
-  --> $DIR/vtable-diamond.rs:15:1
+  --> $DIR/vtable-diamond.rs:34:1
    |
-LL | trait C: A {
-   | ^^^^^^^^^^
+LL | impl D for S {}
+   | ^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/traits/vtable/vtable-dyn-incompatible.rs b/tests/ui/traits/vtable/vtable-dyn-incompatible.rs
index 64a8138bdcf..fb19dec4ace 100644
--- a/tests/ui/traits/vtable/vtable-dyn-incompatible.rs
+++ b/tests/ui/traits/vtable/vtable-dyn-incompatible.rs
@@ -1,15 +1,16 @@
-//@ build-fail
 #![feature(rustc_attrs)]
 
 // Ensure that dyn-incompatible methods in Iterator does not generate
 // vtable entries.
 
-#[rustc_dump_vtable]
 trait A: Iterator {}
-//~^ error vtable
 
 impl<T> A for T where T: Iterator {}
 
+#[rustc_dump_vtable]
+type Test = dyn A<Item=u8>;
+//~^ error vtable
+
 fn foo(_a: &mut dyn A<Item=u8>) {
 }
 
diff --git a/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr b/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr
index e442c3eac00..c80a763998b 100644
--- a/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr
+++ b/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr
@@ -1,16 +1,16 @@
-error: vtable entries for `<std::vec::IntoIter<u8> as A>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
-           Method(<std::vec::IntoIter<u8> as Iterator>::next),
-           Method(<std::vec::IntoIter<u8> as Iterator>::size_hint),
-           Method(<std::vec::IntoIter<u8> as Iterator>::advance_by),
-           Method(<std::vec::IntoIter<u8> as Iterator>::nth),
+           Method(<dyn A<Item = u8> as Iterator>::next - shim(reify)),
+           Method(<dyn A<Item = u8> as Iterator>::size_hint - shim(reify)),
+           Method(<dyn A<Item = u8> as Iterator>::advance_by - shim(reify)),
+           Method(<dyn A<Item = u8> as Iterator>::nth - shim(reify)),
        ]
-  --> $DIR/vtable-dyn-incompatible.rs:8:1
+  --> $DIR/vtable-dyn-incompatible.rs:11:1
    |
-LL | trait A: Iterator {}
-   | ^^^^^^^^^^^^^^^^^
+LL | type Test = dyn A<Item=u8>;
+   | ^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/vtable/vtable-multi-level.rs b/tests/ui/traits/vtable/vtable-multi-level.rs
index bedbf84d303..67bac49f9f6 100644
--- a/tests/ui/traits/vtable/vtable-multi-level.rs
+++ b/tests/ui/traits/vtable/vtable-multi-level.rs
@@ -1,4 +1,3 @@
-//@ build-fail
 #![feature(rustc_attrs)]
 
 //   O --> G --> C --> A
@@ -10,134 +9,126 @@
 //           |-> M --> K
 //                 \-> L
 
-#[rustc_dump_vtable]
 trait A {
-    //~^ error vtable
     fn foo_a(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait B {
-    //~^ error vtable
     fn foo_b(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait C: A + B {
-    //~^ error vtable
     fn foo_c(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait D {
-    //~^ error vtable
     fn foo_d(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait E {
-    //~^ error vtable
     fn foo_e(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait F: D + E {
-    //~^ error vtable
     fn foo_f(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait G: C + F {
     fn foo_g(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait H {
-    //~^ error vtable
     fn foo_h(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait I {
-    //~^ error vtable
     fn foo_i(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait J: H + I {
-    //~^ error vtable
     fn foo_j(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait K {
-    //~^ error vtable
     fn foo_k(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait L {
-    //~^ error vtable
     fn foo_l(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait M: K + L {
-    //~^ error vtable
     fn foo_m(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait N: J + M {
-    //~^ error vtable
     fn foo_n(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait O: G + N {
-    //~^ error vtable
     fn foo_o(&self) {}
 }
 
 struct S;
 
+#[rustc_dump_vtable]
 impl A for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl B for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl C for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl D for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl E for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl F for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl G for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl H for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl I for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl J for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl K for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl L for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl M for S {}
+//~^ ERROR vtable entries
+
+#[rustc_dump_vtable]
 impl N for S {}
-impl O for S {}
+//~^ ERROR vtable entries
 
-macro_rules! monomorphize_vtable {
-    ($trait:ident) => {{
-        fn foo(_ : &dyn $trait) {}
-        foo(&S);
-    }}
-}
+#[rustc_dump_vtable]
+impl O for S {}
+//~^ ERROR vtable entries
 
-fn main() {
-    monomorphize_vtable!(O);
-
-    monomorphize_vtable!(A);
-    monomorphize_vtable!(B);
-    monomorphize_vtable!(C);
-    monomorphize_vtable!(D);
-    monomorphize_vtable!(E);
-    monomorphize_vtable!(F);
-    monomorphize_vtable!(H);
-    monomorphize_vtable!(I);
-    monomorphize_vtable!(J);
-    monomorphize_vtable!(K);
-    monomorphize_vtable!(L);
-    monomorphize_vtable!(M);
-    monomorphize_vtable!(N);
-}
+fn main() {}
diff --git a/tests/ui/traits/vtable/vtable-multi-level.stderr b/tests/ui/traits/vtable/vtable-multi-level.stderr
index c4389e23fc1..961900aa3d2 100644
--- a/tests/ui/traits/vtable/vtable-multi-level.stderr
+++ b/tests/ui/traits/vtable/vtable-multi-level.stderr
@@ -1,134 +1,119 @@
-error: vtable entries for `<S as O>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as A>::foo_a),
-           Method(<S as B>::foo_b),
-           TraitVPtr(<S as B>),
-           Method(<S as C>::foo_c),
-           Method(<S as D>::foo_d),
-           TraitVPtr(<S as D>),
-           Method(<S as E>::foo_e),
-           TraitVPtr(<S as E>),
-           Method(<S as F>::foo_f),
-           TraitVPtr(<S as F>),
-           Method(<S as G>::foo_g),
-           Method(<S as H>::foo_h),
-           TraitVPtr(<S as H>),
-           Method(<S as I>::foo_i),
-           TraitVPtr(<S as I>),
-           Method(<S as J>::foo_j),
-           TraitVPtr(<S as J>),
-           Method(<S as K>::foo_k),
-           TraitVPtr(<S as K>),
-           Method(<S as L>::foo_l),
-           TraitVPtr(<S as L>),
-           Method(<S as M>::foo_m),
-           TraitVPtr(<S as M>),
-           Method(<S as N>::foo_n),
-           TraitVPtr(<S as N>),
-           Method(<S as O>::foo_o),
        ]
-  --> $DIR/vtable-multi-level.rs:97:1
+  --> $DIR/vtable-multi-level.rs:75:1
    |
-LL | trait O: G + N {
-   | ^^^^^^^^^^^^^^
+LL | impl A for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as A>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
-           Method(<S as A>::foo_a),
+           Method(<S as B>::foo_b),
        ]
-  --> $DIR/vtable-multi-level.rs:14:1
+  --> $DIR/vtable-multi-level.rs:79:1
    |
-LL | trait A {
-   | ^^^^^^^
+LL | impl B for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as B>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
+           Method(<S as A>::foo_a),
            Method(<S as B>::foo_b),
+           TraitVPtr(<S as B>),
+           Method(<S as C>::foo_c),
        ]
-  --> $DIR/vtable-multi-level.rs:20:1
+  --> $DIR/vtable-multi-level.rs:83:1
    |
-LL | trait B {
-   | ^^^^^^^
+LL | impl C for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as C>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
-           Method(<S as A>::foo_a),
-           Method(<S as B>::foo_b),
-           TraitVPtr(<S as B>),
-           Method(<S as C>::foo_c),
+           Method(<S as D>::foo_d),
        ]
-  --> $DIR/vtable-multi-level.rs:26:1
+  --> $DIR/vtable-multi-level.rs:87:1
    |
-LL | trait C: A + B {
-   | ^^^^^^^^^^^^^^
+LL | impl D for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as D>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
-           Method(<S as D>::foo_d),
+           Method(<S as E>::foo_e),
        ]
-  --> $DIR/vtable-multi-level.rs:32:1
+  --> $DIR/vtable-multi-level.rs:91:1
    |
-LL | trait D {
-   | ^^^^^^^
+LL | impl E for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as E>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
+           Method(<S as D>::foo_d),
            Method(<S as E>::foo_e),
+           TraitVPtr(<S as E>),
+           Method(<S as F>::foo_f),
        ]
-  --> $DIR/vtable-multi-level.rs:38:1
+  --> $DIR/vtable-multi-level.rs:95:1
    |
-LL | trait E {
-   | ^^^^^^^
+LL | impl F for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as F>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
+           Method(<S as A>::foo_a),
+           Method(<S as B>::foo_b),
+           TraitVPtr(<S as B>),
+           Method(<S as C>::foo_c),
            Method(<S as D>::foo_d),
+           TraitVPtr(<S as D>),
            Method(<S as E>::foo_e),
            TraitVPtr(<S as E>),
            Method(<S as F>::foo_f),
+           TraitVPtr(<S as F>),
+           Method(<S as G>::foo_g),
        ]
-  --> $DIR/vtable-multi-level.rs:44:1
+  --> $DIR/vtable-multi-level.rs:99:1
    |
-LL | trait F: D + E {
-   | ^^^^^^^^^^^^^^
+LL | impl G for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as H>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as H>::foo_h),
        ]
-  --> $DIR/vtable-multi-level.rs:55:1
+  --> $DIR/vtable-multi-level.rs:103:1
    |
-LL | trait H {
-   | ^^^^^^^
+LL | impl H for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as I>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as I>::foo_i),
        ]
-  --> $DIR/vtable-multi-level.rs:61:1
+  --> $DIR/vtable-multi-level.rs:107:1
    |
-LL | trait I {
-   | ^^^^^^^
+LL | impl I for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as J>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
@@ -137,34 +122,34 @@ error: vtable entries for `<S as J>`: [
            TraitVPtr(<S as I>),
            Method(<S as J>::foo_j),
        ]
-  --> $DIR/vtable-multi-level.rs:67:1
+  --> $DIR/vtable-multi-level.rs:111:1
    |
-LL | trait J: H + I {
-   | ^^^^^^^^^^^^^^
+LL | impl J for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as K>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as K>::foo_k),
        ]
-  --> $DIR/vtable-multi-level.rs:73:1
+  --> $DIR/vtable-multi-level.rs:115:1
    |
-LL | trait K {
-   | ^^^^^^^
+LL | impl K for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as L>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as L>::foo_l),
        ]
-  --> $DIR/vtable-multi-level.rs:79:1
+  --> $DIR/vtable-multi-level.rs:119:1
    |
-LL | trait L {
-   | ^^^^^^^
+LL | impl L for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as M>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
@@ -173,12 +158,12 @@ error: vtable entries for `<S as M>`: [
            TraitVPtr(<S as L>),
            Method(<S as M>::foo_m),
        ]
-  --> $DIR/vtable-multi-level.rs:85:1
+  --> $DIR/vtable-multi-level.rs:123:1
    |
-LL | trait M: K + L {
-   | ^^^^^^^^^^^^^^
+LL | impl M for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as N>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
@@ -194,10 +179,46 @@ error: vtable entries for `<S as N>`: [
            TraitVPtr(<S as M>),
            Method(<S as N>::foo_n),
        ]
-  --> $DIR/vtable-multi-level.rs:91:1
+  --> $DIR/vtable-multi-level.rs:127:1
+   |
+LL | impl N for S {}
+   | ^^^^^^^^^^^^
+
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as A>::foo_a),
+           Method(<S as B>::foo_b),
+           TraitVPtr(<S as B>),
+           Method(<S as C>::foo_c),
+           Method(<S as D>::foo_d),
+           TraitVPtr(<S as D>),
+           Method(<S as E>::foo_e),
+           TraitVPtr(<S as E>),
+           Method(<S as F>::foo_f),
+           TraitVPtr(<S as F>),
+           Method(<S as G>::foo_g),
+           Method(<S as H>::foo_h),
+           TraitVPtr(<S as H>),
+           Method(<S as I>::foo_i),
+           TraitVPtr(<S as I>),
+           Method(<S as J>::foo_j),
+           TraitVPtr(<S as J>),
+           Method(<S as K>::foo_k),
+           TraitVPtr(<S as K>),
+           Method(<S as L>::foo_l),
+           TraitVPtr(<S as L>),
+           Method(<S as M>::foo_m),
+           TraitVPtr(<S as M>),
+           Method(<S as N>::foo_n),
+           TraitVPtr(<S as N>),
+           Method(<S as O>::foo_o),
+       ]
+  --> $DIR/vtable-multi-level.rs:131:1
    |
-LL | trait N: J + M {
-   | ^^^^^^^^^^^^^^
+LL | impl O for S {}
+   | ^^^^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/traits/vtable/vtable-multiple.rs b/tests/ui/traits/vtable/vtable-multiple.rs
index beaaf4db6b1..51e20ee20c9 100644
--- a/tests/ui/traits/vtable/vtable-multiple.rs
+++ b/tests/ui/traits/vtable/vtable-multiple.rs
@@ -1,33 +1,29 @@
-//@ build-fail
 #![feature(rustc_attrs)]
 
-#[rustc_dump_vtable]
 trait A {
     fn foo_a(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait B {
-    //~^ error vtable
     fn foo_b(&self) {}
 }
 
-#[rustc_dump_vtable]
 trait C: A + B {
-    //~^ error vtable
     fn foo_c(&self) {}
 }
 
 struct S;
 
+#[rustc_dump_vtable]
 impl A for S {}
+//~^ error vtable
+
+#[rustc_dump_vtable]
 impl B for S {}
-impl C for S {}
+//~^ error vtable
 
-fn foo(c: &dyn C) {}
-fn bar(c: &dyn B) {}
+#[rustc_dump_vtable]
+impl C for S {}
+//~^ error vtable
 
-fn main() {
-    foo(&S);
-    bar(&S);
-}
+fn main() {}
diff --git a/tests/ui/traits/vtable/vtable-multiple.stderr b/tests/ui/traits/vtable/vtable-multiple.stderr
index 0dcd8443309..bae44148baa 100644
--- a/tests/ui/traits/vtable/vtable-multiple.stderr
+++ b/tests/ui/traits/vtable/vtable-multiple.stderr
@@ -1,27 +1,38 @@
-error: vtable entries for `<S as C>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
            Method(<S as A>::foo_a),
+       ]
+  --> $DIR/vtable-multiple.rs:18:1
+   |
+LL | impl A for S {}
+   | ^^^^^^^^^^^^
+
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
            Method(<S as B>::foo_b),
-           TraitVPtr(<S as B>),
-           Method(<S as C>::foo_c),
        ]
-  --> $DIR/vtable-multiple.rs:16:1
+  --> $DIR/vtable-multiple.rs:22:1
    |
-LL | trait C: A + B {
-   | ^^^^^^^^^^^^^^
+LL | impl B for S {}
+   | ^^^^^^^^^^^^
 
-error: vtable entries for `<S as B>`: [
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
+           Method(<S as A>::foo_a),
            Method(<S as B>::foo_b),
+           TraitVPtr(<S as B>),
+           Method(<S as C>::foo_c),
        ]
-  --> $DIR/vtable-multiple.rs:10:1
+  --> $DIR/vtable-multiple.rs:26:1
    |
-LL | trait B {
-   | ^^^^^^^
+LL | impl C for S {}
+   | ^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/vtable/vtable-vacant.rs b/tests/ui/traits/vtable/vtable-vacant.rs
index b3c76815703..b023565c56e 100644
--- a/tests/ui/traits/vtable/vtable-vacant.rs
+++ b/tests/ui/traits/vtable/vtable-vacant.rs
@@ -1,18 +1,14 @@
-//@ build-fail
 #![feature(rustc_attrs)]
 #![feature(negative_impls)]
 
 // B --> A
 
-#[rustc_dump_vtable]
 trait A {
     fn foo_a1(&self) {}
     fn foo_a2(&self) where Self: Send {}
 }
 
-#[rustc_dump_vtable]
 trait B: A {
-    //~^ error vtable
     fn foo_b1(&self) {}
     fn foo_b2(&self) where Self: Send {}
 }
@@ -20,11 +16,12 @@ trait B: A {
 struct S;
 impl !Send for S {}
 
+#[rustc_dump_vtable]
 impl A for S {}
-impl B for S {}
+//~^ error vtable
 
-fn foo(_: &dyn B) {}
+#[rustc_dump_vtable]
+impl B for S {}
+//~^ error vtable
 
-fn main() {
-    foo(&S);
-}
+fn main() {}
diff --git a/tests/ui/traits/vtable/vtable-vacant.stderr b/tests/ui/traits/vtable/vtable-vacant.stderr
index f6961ca010e..ed8466f7f2e 100644
--- a/tests/ui/traits/vtable/vtable-vacant.stderr
+++ b/tests/ui/traits/vtable/vtable-vacant.stderr
@@ -1,4 +1,16 @@
-error: vtable entries for `<S as B>`: [
+error: vtable entries: [
+           MetadataDropInPlace,
+           MetadataSize,
+           MetadataAlign,
+           Method(<S as A>::foo_a1),
+           Vacant,
+       ]
+  --> $DIR/vtable-vacant.rs:20:1
+   |
+LL | impl A for S {}
+   | ^^^^^^^^^^^^
+
+error: vtable entries: [
            MetadataDropInPlace,
            MetadataSize,
            MetadataAlign,
@@ -7,10 +19,10 @@ error: vtable entries for `<S as B>`: [
            Method(<S as B>::foo_b1),
            Vacant,
        ]
-  --> $DIR/vtable-vacant.rs:14:1
+  --> $DIR/vtable-vacant.rs:24:1
    |
-LL | trait B: A {
-   | ^^^^^^^^^^
+LL | impl B for S {}
+   | ^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/type-alias-impl-trait/issue-98604.rs b/tests/ui/type-alias-impl-trait/issue-98604.rs
index 9231e82d9f4..35c25c7f726 100644
--- a/tests/ui/type-alias-impl-trait/issue-98604.rs
+++ b/tests/ui/type-alias-impl-trait/issue-98604.rs
@@ -7,5 +7,5 @@ async fn test() {}
 #[allow(unused_must_use)]
 fn main() {
     Box::new(test) as AsyncFnPtr;
-    //~^ ERROR expected `test` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>
+    //~^ ERROR expected `test` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>
 }
diff --git a/tests/ui/type-alias-impl-trait/issue-98604.stderr b/tests/ui/type-alias-impl-trait/issue-98604.stderr
index 2390b725356..77c6ba3003f 100644
--- a/tests/ui/type-alias-impl-trait/issue-98604.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-98604.stderr
@@ -1,4 +1,4 @@
-error[E0271]: expected `test` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
+error[E0271]: expected `test` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>`
   --> $DIR/issue-98604.rs:9:5
    |
 LL |     Box::new(test) as AsyncFnPtr;
diff --git a/tests/ui/type-alias-impl-trait/issue-98608.rs b/tests/ui/type-alias-impl-trait/issue-98608.rs
index 5e026ea4096..5612ccd6cae 100644
--- a/tests/ui/type-alias-impl-trait/issue-98608.rs
+++ b/tests/ui/type-alias-impl-trait/issue-98608.rs
@@ -4,7 +4,7 @@ fn hi() -> impl Sized {
 
 fn main() {
     let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
-    //~^ ERROR expected `hi` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
+    //~^ ERROR expected `hi` to return `Box<u8>`, but it returns `impl Sized`
     let boxed = b();
     let null = *boxed;
     println!("{null:?}");
diff --git a/tests/ui/type-alias-impl-trait/issue-98608.stderr b/tests/ui/type-alias-impl-trait/issue-98608.stderr
index d5c56636f66..872a6ed4350 100644
--- a/tests/ui/type-alias-impl-trait/issue-98608.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-98608.stderr
@@ -1,4 +1,4 @@
-error[E0271]: expected `hi` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
+error[E0271]: expected `hi` to return `Box<u8>`, but it returns `impl Sized`
   --> $DIR/issue-98608.rs:6:39
    |
 LL | fn hi() -> impl Sized {
diff --git a/tests/ui/type/pattern_types/chars.rs b/tests/ui/type/pattern_types/chars.rs
new file mode 100644
index 00000000000..9073998b387
--- /dev/null
+++ b/tests/ui/type/pattern_types/chars.rs
@@ -0,0 +1,12 @@
+//! Check that chars can be used in ranges
+
+//@ check-pass
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+const LOWERCASE: pattern_type!(char is 'a'..='z') = unsafe { std::mem::transmute('b') };
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/nested.rs b/tests/ui/type/pattern_types/nested.rs
new file mode 100644
index 00000000000..519fb3f05b4
--- /dev/null
+++ b/tests/ui/type/pattern_types/nested.rs
@@ -0,0 +1,26 @@
+//! Check that pattern types can only have specific base types
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+// Undoing an inner pattern type's restrictions should either be forbidden,
+// or still validate correctly.
+const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+// We want to get the most narrowest version that a pattern could be
+const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+const BAD_NESTING4: pattern_type!(() is ..0) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/nested.stderr b/tests/ui/type/pattern_types/nested.stderr
new file mode 100644
index 00000000000..99d3979e98c
--- /dev/null
+++ b/tests/ui/type/pattern_types/nested.stderr
@@ -0,0 +1,62 @@
+error: `(u32) is 1..=` is not a valid base type for range patterns
+  --> $DIR/nested.rs:10:34
+   |
+LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!();
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:10:63
+   |
+LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!();
+   |                                                               ^^^
+
+error: `(i32) is 1..=` is not a valid base type for range patterns
+  --> $DIR/nested.rs:14:35
+   |
+LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!();
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:14:64
+   |
+LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!();
+   |                                                                ^^^^^
+
+error: `(i32) is 1..=` is not a valid base type for range patterns
+  --> $DIR/nested.rs:17:35
+   |
+LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!();
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:17:64
+   |
+LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!();
+   |                                                                ^^^
+
+error: `()` is not a valid base type for range patterns
+  --> $DIR/nested.rs:20:35
+   |
+LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!();
+   |                                   ^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:20:41
+   |
+LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!();
+   |                                         ^^^
+
+error: `f32` is not a valid base type for range patterns
+  --> $DIR/nested.rs:23:35
+   |
+LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!();
+   |                                   ^^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:23:42
+   |
+LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!();
+   |                                          ^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/type/pattern_types/pattern_type_mismatch.rs b/tests/ui/type/pattern_types/pattern_type_mismatch.rs
new file mode 100644
index 00000000000..8d375d7932b
--- /dev/null
+++ b/tests/ui/type/pattern_types/pattern_type_mismatch.rs
@@ -0,0 +1,20 @@
+//! Check that pattern types patterns must be of the type of the base type
+
+//@ known-bug: unknown
+//@ failure-status: 101
+//@ normalize-stderr: "note: .*\n\n" -> ""
+//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> ""
+//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
+//@ normalize-stderr: "(delayed at compiler/rustc_mir_transform/src/lib.rs:)\d+:\d+" -> "$1:LL:CC"
+//@ rustc-env:RUST_BACKTRACE=0
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!();
+
+const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!();
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/pattern_type_mismatch.stderr b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr
new file mode 100644
index 00000000000..ee413133ab3
--- /dev/null
+++ b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr
@@ -0,0 +1,31 @@
+error: internal compiler error: ty::ConstKind::Error constructed but no error reported
+   |
+   = error: internal compiler error: ty::ConstKind::Error constructed but no error reported
+   |
+   = note: delayed at compiler/rustc_mir_build/src/thir/constant.rs:72:21 - disabled backtrace
+   = error: internal compiler error: mir_const_qualif: MIR had errors
+  --> $DIR/pattern_type_mismatch.rs:16:1
+   |
+LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: delayed at compiler/rustc_mir_transform/src/lib.rs::LL:CC - disabled backtrace
+  --> $DIR/pattern_type_mismatch.rs:16:1
+   |
+LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: internal compiler error: mir_const_qualif: MIR had errors
+  --> $DIR/pattern_type_mismatch.rs:18:1
+   |
+LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: delayed at compiler/rustc_mir_transform/src/lib.rs::LL:CC - disabled backtrace
+  --> $DIR/pattern_type_mismatch.rs:18:1
+   |
+LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+query stack during panic:
+end of query stack
diff --git a/tests/ui/type/pattern_types/reverse_range.rs b/tests/ui/type/pattern_types/reverse_range.rs
new file mode 100644
index 00000000000..6a245615f1a
--- /dev/null
+++ b/tests/ui/type/pattern_types/reverse_range.rs
@@ -0,0 +1,14 @@
+//! Check that the range start must be smaller than the range end
+//@ known-bug: unknown
+//@ failure-status: 101
+//@ normalize-stderr: "note: .*\n\n" -> ""
+//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> ""
+//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
+//@ rustc-env:RUST_BACKTRACE=0
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) };
diff --git a/tests/ui/type/pattern_types/reverse_range.stderr b/tests/ui/type/pattern_types/reverse_range.stderr
new file mode 100644
index 00000000000..b714ca7d9ab
--- /dev/null
+++ b/tests/ui/type/pattern_types/reverse_range.stderr
@@ -0,0 +1,17 @@
+error[E0601]: `main` function not found in crate `reverse_range`
+  --> $DIR/reverse_range.rs:14:78
+   |
+LL | const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) };
+   |                                                                              ^ consider adding a `main` function to `$DIR/reverse_range.rs`
+
+
+assertion failed: end <= max_value
+error: the compiler unexpectedly panicked. this is a bug.
+
+query stack during panic:
+#0 [eval_to_allocation_raw] const-evaluating + checking `NONE`
+#1 [eval_to_const_value_raw] simplifying constant for the type system `NONE`
+... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/tests/ui/type/pattern_types/transmute.rs b/tests/ui/type/pattern_types/transmute.rs
new file mode 100644
index 00000000000..cb76b2b938d
--- /dev/null
+++ b/tests/ui/type/pattern_types/transmute.rs
@@ -0,0 +1,32 @@
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+// ok
+fn create<const S: u32, const E: u32>(x: u32) -> pattern_type!(u32 is S..=E) {
+    unsafe { std::mem::transmute(x) }
+}
+
+// ok
+fn unwrap<const S: u32, const E: u32>(x: pattern_type!(u32 is S..=E)) -> u32 {
+    unsafe { std::mem::transmute(x) }
+}
+
+// bad, only when S != u32::MIN or E != u32::MAX will this ok
+fn non_base_ty_transmute<const S: u32, const E: u32>(
+    x: Option<pattern_type!(u32 is S..=E)>,
+) -> u32 {
+    unsafe { std::mem::transmute(x) }
+    //~^ ERROR types of different sizes
+}
+
+// bad, only when S = u32::MIN and E = u32::MAX will this ok
+fn wrapped_transmute<const S: u32, const E: u32>(
+    x: Option<pattern_type!(u32 is S..=E)>,
+) -> Option<u32> {
+    unsafe { std::mem::transmute(x) }
+    //~^ ERROR types of different sizes
+}
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/transmute.stderr b/tests/ui/type/pattern_types/transmute.stderr
new file mode 100644
index 00000000000..578549b515c
--- /dev/null
+++ b/tests/ui/type/pattern_types/transmute.stderr
@@ -0,0 +1,21 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute.rs:20:14
+   |
+LL |     unsafe { std::mem::transmute(x) }
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `Option<(u32) is S..=E>` (size can vary because of u32)
+   = note: target type: `u32` (32 bits)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute.rs:28:14
+   |
+LL |     unsafe { std::mem::transmute(x) }
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `Option<(u32) is S..=E>` (size can vary because of u32)
+   = note: target type: `Option<u32>` (64 bits)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/type/pattern_types/validity.rs b/tests/ui/type/pattern_types/validity.rs
new file mode 100644
index 00000000000..77a4e72f675
--- /dev/null
+++ b/tests/ui/type/pattern_types/validity.rs
@@ -0,0 +1,37 @@
+//! Check that pattern types have their validity checked
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) };
+//~^ ERROR: it is undefined behavior to use this value
+
+const BAD_UNINIT: pattern_type!(u32 is 1..) =
+    //~^ ERROR: evaluation of constant value failed
+    unsafe { std::mem::transmute(std::mem::MaybeUninit::<u32>::uninit()) };
+
+const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) };
+//~^ ERROR: evaluation of constant value failed
+
+const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0);
+//~^ ERROR: it is undefined behavior to use this value
+
+struct Foo(Bar);
+struct Bar(pattern_type!(u32 is 1..));
+
+const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) }));
+//~^ ERROR: it is undefined behavior to use this value
+
+const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') =
+    //~^ ERROR: evaluation of constant value failed
+    unsafe { std::mem::transmute(std::mem::MaybeUninit::<u32>::uninit()) };
+
+const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') };
+//~^ ERROR: it is undefined behavior to use this value
+
+const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) };
+//~^ ERROR: it is undefined behavior to use this value
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr
new file mode 100644
index 00000000000..5bc18cfba3f
--- /dev/null
+++ b/tests/ui/type/pattern_types/validity.stderr
@@ -0,0 +1,79 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validity.rs:8:1
+   |
+LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               00 00 00 00                                     │ ....
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/validity.rs:11:1
+   |
+LL | const BAD_UNINIT: pattern_type!(u32 is 1..) =
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/validity.rs:15:1
+   |
+LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validity.rs:18:1
+   |
+LL | const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               00 00 00 00 00 00 00 00                         │ ........
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validity.rs:24:1
+   |
+LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) }));
+   | ^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               00 00 00 00                                     │ ....
+           }
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/validity.rs:27:1
+   |
+LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') =
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validity.rs:31:1
+   |
+LL | const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 97, but expected something in the range 65..=89
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               61 00 00 00                                     │ a...
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/validity.rs:34:1
+   |
+LL | const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 4, align: 4) {
+               ff ff ff ff                                     │ ....
+           }
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr
index 71717c6945e..eea2e75a238 100644
--- a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr
+++ b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr
@@ -17,7 +17,7 @@ LL |     let y = x as dyn MyAdd<i32>;
    |                  ^^^^^^^^^^^^^^ `MyAdd` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:6:55
    |
 LL | trait MyAdd<Rhs=Self> { fn add(&self, other: &Rhs) -> Self; }
diff --git a/tests/ui/type_length_limit.rs b/tests/ui/type_length_limit.rs
index 87f5ffd76d7..b629455aced 100644
--- a/tests/ui/type_length_limit.rs
+++ b/tests/ui/type_length_limit.rs
@@ -2,6 +2,9 @@
 //@ compile-flags: -Copt-level=0 -Zenforce-type-length-limit
 //~^^ ERROR reached the type-length limit
 
+// The regex below normalizes the long type file name to make it suitable for compare-modes.
+//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'"
+
 // Test that the type length limit can be changed.
 // The exact type depends on optimizations, so disable them.
 
diff --git a/tests/ui/type_length_limit.stderr b/tests/ui/type_length_limit.stderr
index 83353547d34..d913b661c6f 100644
--- a/tests/ui/type_length_limit.stderr
+++ b/tests/ui/type_length_limit.stderr
@@ -1,11 +1,11 @@
 error: reached the type-length limit while instantiating `std::mem::drop::<Option<((((..., ..., ...), ..., ...), ..., ...), ..., ...)>>`
-  --> $DIR/type_length_limit.rs:32:5
+  --> $DIR/type_length_limit.rs:35:5
    |
 LL |     drop::<Option<A>>(None);
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding a `#![type_length_limit="4010"]` attribute to your crate
-   = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
+   = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt'
 
 error: reached the type-length limit while instantiating `<{closure@rt::lang_start<()>::{closure#0}} as FnMut<()>>::call_mut`
    |
diff --git a/tests/ui/typeck/issue-107775.stderr b/tests/ui/typeck/issue-107775.stderr
index 180b0183a3f..1be26897469 100644
--- a/tests/ui/typeck/issue-107775.stderr
+++ b/tests/ui/typeck/issue-107775.stderr
@@ -6,10 +6,12 @@ LL |         map.insert(1, Struct::do_something);
    |         |
    |         ... which causes `map` to have type `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
 LL |         Self { map }
-   |                ^^^ expected `HashMap<u16, fn(u8) -> Pin<...>>`, found `HashMap<{integer}, ...>`
+   |                ^^^ expected `HashMap<u16, fn(u8) -> Pin<Box<...>>>`, found `HashMap<{integer}, ...>`
    |
    = note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
               found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `<Struct as Trait>::do_something::<'_> as fn(u8) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr
index 1bcc0dbaf67..92ad83c3300 100644
--- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr
+++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr
@@ -9,6 +9,8 @@ error: the constant `N` is not of type `usize`
    |
 LL |     fn func<const N: u32>() -> [(); N];
    |                                ^^^^^^^ expected `usize`, found `u32`
+   |
+   = note: the length of array `[(); N]` must be type `usize`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr
index 1bcc0dbaf67..92ad83c3300 100644
--- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr
+++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr
@@ -9,6 +9,8 @@ error: the constant `N` is not of type `usize`
    |
 LL |     fn func<const N: u32>() -> [(); N];
    |                                ^^^^^^^ expected `usize`, found `u32`
+   |
+   = note: the length of array `[(); N]` must be type `usize`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/typeck/path-to-method-sugg-unresolved-expr.rs b/tests/ui/typeck/path-to-method-sugg-unresolved-expr.rs
index 7b4f62fea0c..e095850879c 100644
--- a/tests/ui/typeck/path-to-method-sugg-unresolved-expr.rs
+++ b/tests/ui/typeck/path-to-method-sugg-unresolved-expr.rs
@@ -5,6 +5,6 @@ fn main() {
     let page_size = page_size::get();
     //~^ ERROR failed to resolve: use of unresolved module or unlinked crate `page_size`
     //~| NOTE use of unresolved module or unlinked crate `page_size`
-    //@[cargo-invoked]~^^^ HELP if you wanted to use a crate named `page_size`, use `cargo add
-    //@[only-rustc]~^^^^ HELP you might be missing a crate named `page_size`
+    //[cargo-invoked]~^^^ HELP if you wanted to use a crate named `page_size`, use `cargo add
+    //[only-rustc]~^^^^ HELP you might be missing a crate named `page_size`
 }
diff --git a/tests/ui/typeck/return_type_containing_closure.rs b/tests/ui/typeck/return_type_containing_closure.rs
index b81cac0a58a..a9bb89bae2d 100644
--- a/tests/ui/typeck/return_type_containing_closure.rs
+++ b/tests/ui/typeck/return_type_containing_closure.rs
@@ -2,7 +2,7 @@
 fn foo() { //~ HELP try adding a return type
     vec!['a'].iter().map(|c| c)
     //~^ ERROR mismatched types [E0308]
-    //~| NOTE expected `()`, found `Map<Iter<'_, char>, ...>`
+    //~| NOTE expected `()`, found `Map<Iter<'_, char>, {closure@...}>`
     //~| NOTE expected unit type `()`
     //~| HELP consider using a semicolon here
 }
diff --git a/tests/ui/typeck/return_type_containing_closure.stderr b/tests/ui/typeck/return_type_containing_closure.stderr
index 3f14650a82c..a60bf79a57b 100644
--- a/tests/ui/typeck/return_type_containing_closure.stderr
+++ b/tests/ui/typeck/return_type_containing_closure.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/return_type_containing_closure.rs:3:5
    |
 LL |     vec!['a'].iter().map(|c| c)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Map<Iter<'_, char>, ...>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Map<Iter<'_, char>, {closure@...}>`
    |
    = note: expected unit type `()`
                  found struct `Map<std::slice::Iter<'_, char>, {closure@$DIR/return_type_containing_closure.rs:3:26: 3:29}>`
diff --git a/tests/ui/union/union-derive-eq.next.stderr b/tests/ui/union/union-derive-eq.next.stderr
index 3952b1f1284..151ceebe1ba 100644
--- a/tests/ui/union/union-derive-eq.next.stderr
+++ b/tests/ui/union/union-derive-eq.next.stderr
@@ -7,6 +7,8 @@ LL | union U2 {
 LL |     a: PartialEqNotEq,
    |     ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
    |
+note: required by a bound in `AssertParamIsEq`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]`
    |
diff --git a/tests/ui/unsafe-binders/expr.rs b/tests/ui/unsafe-binders/expr.rs
index 0fe68751f0a..d437d8f8ac0 100644
--- a/tests/ui/unsafe-binders/expr.rs
+++ b/tests/ui/unsafe-binders/expr.rs
@@ -1,3 +1,5 @@
+//@ check-pass
+
 #![feature(unsafe_binders)]
 //~^ WARN the feature `unsafe_binders` is incomplete
 
@@ -7,8 +9,6 @@ fn main() {
     unsafe {
     let x = 1;
         let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
-        //~^ ERROR unsafe binder casts are not fully implemented
         let rx = *unwrap_binder!(binder);
-        //~^ ERROR unsafe binder casts are not fully implemented
     }
 }
diff --git a/tests/ui/unsafe-binders/expr.stderr b/tests/ui/unsafe-binders/expr.stderr
index 78a288e10a3..07026e18e12 100644
--- a/tests/ui/unsafe-binders/expr.stderr
+++ b/tests/ui/unsafe-binders/expr.stderr
@@ -1,5 +1,5 @@
 warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/expr.rs:1:12
+  --> $DIR/expr.rs:3:12
    |
 LL | #![feature(unsafe_binders)]
    |            ^^^^^^^^^^^^^^
@@ -7,17 +7,5 @@ LL | #![feature(unsafe_binders)]
    = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: unsafe binder casts are not fully implemented
-  --> $DIR/expr.rs:9:55
-   |
-LL |         let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
-   |                                                       ^^
-
-error: unsafe binder casts are not fully implemented
-  --> $DIR/expr.rs:11:34
-   |
-LL |         let rx = *unwrap_binder!(binder);
-   |                                  ^^^^^^
-
-error: aborting due to 2 previous errors; 1 warning emitted
+warning: 1 warning emitted
 
diff --git a/tests/ui/unsafe-binders/mismatch.rs b/tests/ui/unsafe-binders/mismatch.rs
index 731fe2d1ce9..840d938cbe9 100644
--- a/tests/ui/unsafe-binders/mismatch.rs
+++ b/tests/ui/unsafe-binders/mismatch.rs
@@ -5,38 +5,31 @@ use std::unsafe_binder::{wrap_binder, unwrap_binder};
 
 fn a() {
     let _: unsafe<'a> &'a i32 = wrap_binder!(&());
-    //~^ ERROR unsafe binder casts are not fully implemented
-    //~| ERROR mismatched types
+    //~^ ERROR mismatched types
 }
 
 fn b() {
     let _: i32 = wrap_binder!(&());
-    //~^ ERROR unsafe binder casts are not fully implemented
-    //~| ERROR `wrap_binder!()` can only wrap into unsafe binder
+    //~^ ERROR `wrap_binder!()` can only wrap into unsafe binder
 }
 
 fn c() {
     let y = 1;
     unwrap_binder!(y);
-    //~^ ERROR unsafe binder casts are not fully implemented
-    //~| ERROR expected unsafe binder, found integer as input
+    //~^ ERROR expected unsafe binder, found integer as input
 }
 
 fn d() {
     let unknown = Default::default();
+    //~^ ERROR type annotations needed
     unwrap_binder!(unknown);
-    //~^ ERROR unsafe binder casts are not fully implemented
-    // FIXME(unsafe_binders): This should report ambiguity once we've removed
-    // the error above which taints the infcx.
 }
 
 fn e() {
     let x = wrap_binder!(&42);
-    //~^ ERROR unsafe binder casts are not fully implemented
+    //~^ ERROR type annotations needed
     // Currently, type inference doesn't flow backwards for unsafe binders.
     // It could, perhaps, but that may cause even more surprising corners.
-    // FIXME(unsafe_binders): This should report ambiguity once we've removed
-    // the error above which taints the infcx.
     let _: unsafe<'a> &'a i32 = x;
 }
 
diff --git a/tests/ui/unsafe-binders/mismatch.stderr b/tests/ui/unsafe-binders/mismatch.stderr
index a720e5dbdc1..f64db92eb65 100644
--- a/tests/ui/unsafe-binders/mismatch.stderr
+++ b/tests/ui/unsafe-binders/mismatch.stderr
@@ -7,12 +7,6 @@ LL | #![feature(unsafe_binders)]
    = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: unsafe binder casts are not fully implemented
-  --> $DIR/mismatch.rs:7:46
-   |
-LL |     let _: unsafe<'a> &'a i32 = wrap_binder!(&());
-   |                                              ^^^
-
 error[E0308]: mismatched types
   --> $DIR/mismatch.rs:7:46
    |
@@ -22,14 +16,8 @@ LL |     let _: unsafe<'a> &'a i32 = wrap_binder!(&());
    = note: expected reference `&i32`
               found reference `&()`
 
-error: unsafe binder casts are not fully implemented
-  --> $DIR/mismatch.rs:13:31
-   |
-LL |     let _: i32 = wrap_binder!(&());
-   |                               ^^^
-
 error: `wrap_binder!()` can only wrap into unsafe binder, not `i32`
-  --> $DIR/mismatch.rs:13:18
+  --> $DIR/mismatch.rs:12:18
    |
 LL |     let _: i32 = wrap_binder!(&());
    |                  ^^^^^^^^^^^^^^^^^
@@ -37,32 +25,35 @@ LL |     let _: i32 = wrap_binder!(&());
    = note: unsafe binders are the only valid output of wrap
    = note: this error originates in the macro `wrap_binder` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: unsafe binder casts are not fully implemented
-  --> $DIR/mismatch.rs:20:20
-   |
-LL |     unwrap_binder!(y);
-   |                    ^
-
 error: expected unsafe binder, found integer as input of `unwrap_binder!()`
-  --> $DIR/mismatch.rs:20:20
+  --> $DIR/mismatch.rs:18:20
    |
 LL |     unwrap_binder!(y);
    |                    ^
    |
    = note: only an unsafe binder type can be unwrapped
 
-error: unsafe binder casts are not fully implemented
-  --> $DIR/mismatch.rs:27:20
+error[E0282]: type annotations needed
+  --> $DIR/mismatch.rs:23:9
    |
+LL |     let unknown = Default::default();
+   |         ^^^^^^^
+LL |
 LL |     unwrap_binder!(unknown);
-   |                    ^^^^^^^
+   |                    ------- type must be known at this point
+   |
+help: consider giving `unknown` an explicit type
+   |
+LL |     let unknown: /* Type */ = Default::default();
+   |                ++++++++++++
 
-error: unsafe binder casts are not fully implemented
-  --> $DIR/mismatch.rs:34:26
+error[E0282]: type annotations needed
+  --> $DIR/mismatch.rs:29:26
    |
 LL |     let x = wrap_binder!(&42);
-   |                          ^^^
+   |                          ^^^ cannot infer type
 
-error: aborting due to 8 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0282, E0308.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/unsafe-binders/moves.rs b/tests/ui/unsafe-binders/moves.rs
new file mode 100644
index 00000000000..5bfcee62402
--- /dev/null
+++ b/tests/ui/unsafe-binders/moves.rs
@@ -0,0 +1,41 @@
+//@ known-bug: unknown
+
+#![feature(unsafe_binders)]
+// FIXME(unsafe_binders) ~^ WARN the feature `unsafe_binders` is incomplete
+
+use std::unsafe_binder::{wrap_binder, unwrap_binder};
+use std::mem::{drop, ManuallyDrop};
+
+struct NotCopyInner;
+type NotCopy = ManuallyDrop<NotCopyInner>;
+
+fn use_after_wrap() {
+    unsafe {
+        let base = NotCopy;
+        let binder: unsafe<> NotCopy = wrap_binder!(base);
+        drop(base);
+        // FIXME(unsafe_binders) ~^ ERROR use of moved value: `base`
+    }
+}
+
+fn move_out_of_wrap() {
+    unsafe {
+        let binder: unsafe<> NotCopy = wrap_binder!(NotCopy);
+        drop(unwrap_binder!(binder));
+        drop(unwrap_binder!(binder));
+        // FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder`
+    }
+}
+
+fn not_conflicting() {
+    unsafe {
+        let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
+        drop(unwrap_binder!(binder).0);
+        drop(unwrap_binder!(binder).1);
+        // ^ NOT a problem.
+        drop(unwrap_binder!(binder).0);
+        // FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder.0`
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/unsafe-binders/moves.stderr b/tests/ui/unsafe-binders/moves.stderr
new file mode 100644
index 00000000000..ca507964008
--- /dev/null
+++ b/tests/ui/unsafe-binders/moves.stderr
@@ -0,0 +1,85 @@
+error[E0423]: expected value, found type alias `NotCopy`
+  --> $DIR/moves.rs:14:20
+   |
+LL |         let base = NotCopy;
+   |                    ^^^^^^^
+   |
+   = note: can't use a type alias as a constructor
+
+error[E0423]: expected value, found type alias `NotCopy`
+  --> $DIR/moves.rs:23:53
+   |
+LL |         let binder: unsafe<> NotCopy = wrap_binder!(NotCopy);
+   |                                                     ^^^^^^^
+   |
+   = note: can't use a type alias as a constructor
+
+error[E0423]: expected value, found type alias `NotCopy`
+  --> $DIR/moves.rs:32:65
+   |
+LL |         let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
+   |                                                                 ^^^^^^^
+   |
+   = note: can't use a type alias as a constructor
+
+error[E0423]: expected value, found type alias `NotCopy`
+  --> $DIR/moves.rs:32:74
+   |
+LL |         let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
+   |                                                                          ^^^^^^^
+   |
+   = note: can't use a type alias as a constructor
+
+warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/moves.rs:3:12
+   |
+LL | #![feature(unsafe_binders)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied
+  --> $DIR/moves.rs:15:21
+   |
+LL |         let binder: unsafe<> NotCopy = wrap_binder!(base);
+   |                     ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner`
+   |
+   = note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy`
+help: consider annotating `NotCopyInner` with `#[derive(Copy)]`
+   |
+LL + #[derive(Copy)]
+LL | struct NotCopyInner;
+   |
+
+error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied
+  --> $DIR/moves.rs:23:21
+   |
+LL |         let binder: unsafe<> NotCopy = wrap_binder!(NotCopy);
+   |                     ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner`
+   |
+   = note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy`
+help: consider annotating `NotCopyInner` with `#[derive(Copy)]`
+   |
+LL + #[derive(Copy)]
+LL | struct NotCopyInner;
+   |
+
+error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied
+  --> $DIR/moves.rs:32:21
+   |
+LL |         let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner`
+   |
+   = note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy`
+   = note: required because it appears within the type `(ManuallyDrop<NotCopyInner>, ManuallyDrop<NotCopyInner>)`
+help: consider annotating `NotCopyInner` with `#[derive(Copy)]`
+   |
+LL + #[derive(Copy)]
+LL | struct NotCopyInner;
+   |
+
+error: aborting due to 7 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0277, E0423.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr
index 7be327e61d1..0c293e3576d 100644
--- a/tests/ui/wf/issue-87495.stderr
+++ b/tests/ui/wf/issue-87495.stderr
@@ -5,7 +5,7 @@ LL |     const CONST: (bool, dyn T);
    |                         ^^^^^ `T` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/issue-87495.rs:4:11
    |
 LL | trait T {
diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr
index 0b7f4cd4362..f3e4f2a63e9 100644
--- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr
+++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr
@@ -5,7 +5,7 @@ LL |     let t_box: Box<dyn Trait> = Box::new(S);
    |                                 ^^^^^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14
    |
 LL | trait Trait: Sized {}
@@ -22,7 +22,7 @@ LL |     takes_box(Box::new(S));
    |               ^^^^^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14
    |
 LL | trait Trait: Sized {}
@@ -39,7 +39,7 @@ LL |     Box::new(S) as Box<dyn Trait>;
    |     ^^^^^^^^^^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14
    |
 LL | trait Trait: Sized {}
diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr
index 3f50e1192cf..716d0e78ff1 100644
--- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr
+++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr
@@ -5,7 +5,7 @@ LL |     let t: &dyn Trait = &S;
    |                         ^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14
    |
 LL | trait Trait: Sized {}
@@ -22,7 +22,7 @@ LL |     takes_trait(&S);
    |                 ^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14
    |
 LL | trait Trait: Sized {}
@@ -39,7 +39,7 @@ LL |     &S as &dyn Trait;
    |     ^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14
    |
 LL | trait Trait: Sized {}
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
index 8f68f9c5b6b..a7405ce4caa 100644
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
+++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
@@ -19,7 +19,7 @@ LL |         Some(()) => &S,
    |                     ^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14
    |
 LL | trait Trait: Sized {}
@@ -40,7 +40,7 @@ LL |         None => &R,
    |                 ^^ `Trait` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14
    |
 LL | trait Trait: Sized {}
diff --git a/tests/ui/wf/wf-dyn-incompatible.stderr b/tests/ui/wf/wf-dyn-incompatible.stderr
index 1803376aaa1..e61b37d9293 100644
--- a/tests/ui/wf/wf-dyn-incompatible.stderr
+++ b/tests/ui/wf/wf-dyn-incompatible.stderr
@@ -5,7 +5,7 @@ LL |     let _x: &dyn A;
    |             ^^^^^^ `A` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
   --> $DIR/wf-dyn-incompatible.rs:5:23
    |
 LL | trait A {
diff --git a/tests/ui/wf/wf-fn-where-clause.stderr b/tests/ui/wf/wf-fn-where-clause.stderr
index d73376e9861..b419bc8347f 100644
--- a/tests/ui/wf/wf-fn-where-clause.stderr
+++ b/tests/ui/wf/wf-fn-where-clause.stderr
@@ -22,7 +22,7 @@ LL | fn bar() where Vec<dyn Copy>:, {}
    |
    = note: the trait is not dyn compatible because it requires `Self: Sized`
    = note: for a trait to be dyn compatible it needs to allow building a vtable
-           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+           for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
 
 error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time
   --> $DIR/wf-fn-where-clause.rs:12:16
diff --git a/tests/ui/wf/wf-normalization-sized.next.stderr b/tests/ui/wf/wf-normalization-sized.next.stderr
index 1e898fb7b78..83b56bb6b19 100644
--- a/tests/ui/wf/wf-normalization-sized.next.stderr
+++ b/tests/ui/wf/wf-normalization-sized.next.stderr
@@ -5,6 +5,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
    |           ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
+   = note: slice and array elements must have `Sized` type
 
 error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
   --> $DIR/wf-normalization-sized.rs:19:11
@@ -13,6 +14,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
    |           ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
+   = note: slice and array elements must have `Sized` type
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -22,6 +24,8 @@ LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
    |           ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `str`
+note: required by an implicit `Sized` bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> $DIR/wf-normalization-sized.rs:22:11
@@ -30,6 +34,8 @@ LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
    |           ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `str`
+note: required by an implicit `Sized` bound in `Vec`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/wf/wf-trait-default-fn-ret.rs b/tests/ui/wf/wf-trait-default-fn-ret.rs
index 2103dae8d23..a7f83dcf678 100644
--- a/tests/ui/wf/wf-trait-default-fn-ret.rs
+++ b/tests/ui/wf/wf-trait-default-fn-ret.rs
@@ -1,5 +1,4 @@
-// Check that we test WF conditions for fn arguments. Because the
-// current code is so goofy, this is only a warning for now.
+// Check that we test WF conditions for fn arguments.
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
diff --git a/tests/ui/wf/wf-trait-default-fn-ret.stderr b/tests/ui/wf/wf-trait-default-fn-ret.stderr
index f749ac7b1b3..f0d1b55edc4 100644
--- a/tests/ui/wf/wf-trait-default-fn-ret.stderr
+++ b/tests/ui/wf/wf-trait-default-fn-ret.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `Self: Eq` is not satisfied
-  --> $DIR/wf-trait-default-fn-ret.rs:11:22
+  --> $DIR/wf-trait-default-fn-ret.rs:10:22
    |
 LL |     fn bar(&self) -> Bar<Self> {
    |                      ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
    |
 note: required by a bound in `Bar`
-  --> $DIR/wf-trait-default-fn-ret.rs:8:14
+  --> $DIR/wf-trait-default-fn-ret.rs:7:14
    |
 LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
    |              ^^ required by this bound in `Bar`
diff --git a/tests/ui/wf/wf-trait-fn-arg.next.stderr b/tests/ui/wf/wf-trait-fn-arg.next.stderr
index c55dc5c8a12..d5dd36fad6d 100644
--- a/tests/ui/wf/wf-trait-fn-arg.next.stderr
+++ b/tests/ui/wf/wf-trait-fn-arg.next.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied
 LL |     fn bar(&self, x: &Bar<Self>);
    |                       ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
    |
+note: required by a bound in `Bar`
+  --> $DIR/wf-trait-fn-arg.rs:11:15
+   |
+LL | struct Bar<T: Eq + ?Sized> {
+   |               ^^ required by this bound in `Bar`
 help: consider further restricting `Self`
    |
 LL |     fn bar(&self, x: &Bar<Self>) where Self: Eq;
diff --git a/tests/ui/wf/wf-trait-fn-ret.next.stderr b/tests/ui/wf/wf-trait-fn-ret.next.stderr
index b3dca17672d..0ad786c2fd5 100644
--- a/tests/ui/wf/wf-trait-fn-ret.next.stderr
+++ b/tests/ui/wf/wf-trait-fn-ret.next.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied
 LL |     fn bar(&self) -> &Bar<Self>;
    |                       ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
    |
+note: required by a bound in `Bar`
+  --> $DIR/wf-trait-fn-ret.rs:10:15
+   |
+LL | struct Bar<T: Eq + ?Sized> {
+   |               ^^ required by this bound in `Bar`
 help: consider further restricting `Self`
    |
 LL |     fn bar(&self) -> &Bar<Self> where Self: Eq;
diff --git a/tests/ui/wf/wf-trait-fn-where-clause.next.stderr b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr
index 8c8a5fa3e70..db5454d0f3c 100644
--- a/tests/ui/wf/wf-trait-fn-where-clause.next.stderr
+++ b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied
 LL |         Bar<Self>: Copy;
    |                    ^^^^ the trait `Eq` is not implemented for `Self`
    |
+note: required by a bound in `Bar`
+  --> $DIR/wf-trait-fn-where-clause.rs:10:15
+   |
+LL | struct Bar<T: Eq + ?Sized> {
+   |               ^^ required by this bound in `Bar`
 help: consider further restricting `Self`
    |
 LL |         Bar<Self>: Copy, Self: Eq;
diff --git a/triagebot.toml b/triagebot.toml
index d09d5eceeb8..49cf1213987 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1023,10 +1023,8 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
 users_on_vacation = [
     "jyn514",
     "nnethercote",
-    "spastorino",
     "workingjubilee",
     "kobzol",
-    "jieyouxu",
 ]
 
 [[assign.warn_non_default_branch.exceptions]]