about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock33
-rw-r--r--compiler/rustc_abi/src/layout.rs4
-rw-r--r--compiler/rustc_abi/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/ast.rs68
-rw-r--r--compiler/rustc_ast/src/ast_traits.rs33
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs17
-rw-r--r--compiler/rustc_ast/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs3
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs80
-rw-r--r--compiler/rustc_ast/src/util/classify.rs81
-rw-r--r--compiler/rustc_ast/src/visit.rs1
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl5
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs11
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs9
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs25
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs15
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs7
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs24
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs5
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs8
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs106
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs92
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs31
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs17
-rw-r--r--compiler/rustc_borrowck/src/facts.rs28
-rw-r--r--compiler/rustc_borrowck/src/lib.rs10
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_invalidations.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs101
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs87
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs9
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl11
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs20
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs39
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs40
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs24
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs43
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs117
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs742
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath/tests.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/locals.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs18
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs10
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs19
-rw-r--r--compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs1
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs159
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs160
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs2
-rw-r--r--compiler/rustc_data_structures/src/sip128.rs11
-rw-r--r--compiler/rustc_data_structures/src/sync.rs4
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs21
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0502.md5
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs14
-rw-r--r--compiler/rustc_errors/src/emitter.rs23
-rw-r--r--compiler/rustc_expand/src/config.rs29
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs12
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs74
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs32
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/lang_items.rs13
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl6
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs116
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs112
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs74
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs (renamed from compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs)62
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs39
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs84
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs66
-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.rs90
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/utils.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs57
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs56
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl26
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs158
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs106
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs39
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs50
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs52
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs100
-rw-r--r--compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs27
-rw-r--r--compiler/rustc_index/src/lib.rs5
-rw-r--r--compiler/rustc_index/src/vec.rs5
-rw-r--r--compiler/rustc_index_macros/src/lib.rs5
-rw-r--r--compiler/rustc_index_macros/src/newtype.rs4
-rw-r--r--compiler/rustc_infer/Cargo.toml2
-rw-r--r--compiler/rustc_infer/src/infer/context.rs176
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs857
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs421
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/region.rs1259
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs17
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs266
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs1
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs6
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs33
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs36
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs4
-rw-r--r--compiler/rustc_infer/src/infer/relate/glb.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/lattice.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/lub.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/relate/type_relating.rs4
-rw-r--r--compiler/rustc_infer/src/traits/util.rs380
-rw-r--r--compiler/rustc_interface/src/lib.rs2
-rw-r--r--compiler/rustc_interface/src/queries.rs61
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl3
-rw-r--r--compiler/rustc_lint/src/async_fn_in_trait.rs2
-rw-r--r--compiler/rustc_lint/src/context/diagnostics/check_cfg.rs18
-rw-r--r--compiler/rustc_lint/src/internal.rs4
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/lints.rs7
-rw-r--r--compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs155
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs4
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs4
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs4
-rw-r--r--compiler/rustc_lint/src/unused.rs4
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs56
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp7
-rw-r--r--compiler/rustc_middle/messages.ftl6
-rw-r--r--compiler/rustc_middle/src/error.rs14
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs34
-rw-r--r--compiler/rustc_middle/src/middle/dependency_format.rs6
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs4
-rw-r--r--compiler/rustc_middle/src/middle/limits.rs2
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs11
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs73
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs4
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs13
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs44
-rw-r--r--compiler/rustc_middle/src/mir/query.rs3
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs31
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs13
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs11
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs1
-rw-r--r--compiler/rustc_middle/src/traits/util.rs62
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs4
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs7
-rw-r--r--compiler/rustc_middle/src/ty/context.rs177
-rw-r--r--compiler/rustc_middle/src/ty/elaborate_impl.rs84
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs368
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs13
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs248
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs18
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs32
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs53
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs12
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs14
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs10
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs17
-rw-r--r--compiler/rustc_middle/src/util/call_kind.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/coverageinfo.rs107
-rw-r--r--compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs12
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs39
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs86
-rw-r--r--compiler/rustc_mir_build/src/lints.rs18
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/lattice.rs14
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs191
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs49
-rw-r--r--compiler/rustc_mir_transform/src/cost_checker.rs36
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs9
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mappings.rs22
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs80
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs7
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs44
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs6
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs20
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs16
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs67
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs2
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs20
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs1
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs2
-rw-r--r--compiler/rustc_mir_transform/src/mentioned_items.rs2
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs1
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs49
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs77
-rw-r--r--compiler/rustc_monomorphize/messages.ftl5
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs90
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs13
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/coherence.rs469
-rw-r--r--compiler/rustc_next_trait_solver/src/delegate.rs111
-rw-r--r--compiler/rustc_next_trait_solver/src/lib.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/relate.rs15
-rw-r--r--compiler/rustc_next_trait_solver/src/relate/combine.rs34
-rw-r--r--compiler/rustc_next_trait_solver/src/resolve.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs120
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs14
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/search_graph.rs52
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs11
-rw-r--r--compiler/rustc_parse/messages.ftl4
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs6
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs162
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs23
-rw-r--r--compiler/rustc_parse/src/parser/path.rs27
-rw-r--r--compiler/rustc_passes/src/abi_test.rs2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs42
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs2
-rw-r--r--compiler/rustc_passes/src/layout_test.rs2
-rw-r--r--compiler/rustc_passes/src/reachable.rs2
-rw-r--r--compiler/rustc_resolve/Cargo.toml2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs10
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs23
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs18
-rw-r--r--compiler/rustc_resolve/src/late.rs3
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs44
-rw-r--r--compiler/rustc_resolve/src/lib.rs24
-rw-r--r--compiler/rustc_resolve/src/macros.rs9
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs14
-rw-r--r--compiler/rustc_serialize/src/opaque.rs2
-rw-r--r--compiler/rustc_session/src/options.rs6
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs10
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs11
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs698
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs (renamed from compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs)1218
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/infer_ctxt_ext.rs (renamed from compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs)4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs385
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs (renamed from compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs)11
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs197
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs (renamed from compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs)177
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs11
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs189
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs454
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs136
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs182
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs61
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs14
-rw-r--r--compiler/rustc_traits/src/codegen.rs2
-rw-r--r--compiler/rustc_traits/src/normalize_projection_ty.rs2
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs4
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs4
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs6
-rw-r--r--compiler/rustc_ty_utils/src/sig_types.rs2
-rw-r--r--compiler/rustc_type_ir/src/binder.rs6
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs305
-rw-r--r--compiler/rustc_type_ir/src/fast_reject.rs397
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs98
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs57
-rw-r--r--compiler/rustc_type_ir/src/interner.rs33
-rw-r--r--compiler/rustc_type_ir/src/lang_items.rs6
-rw-r--r--compiler/rustc_type_ir/src/lib.rs7
-rw-r--r--compiler/rustc_type_ir/src/outlives.rs228
-rw-r--r--library/alloc/src/boxed.rs6
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs18
-rw-r--r--library/alloc/src/collections/btree/set/tests.rs6
-rw-r--r--library/alloc/src/collections/linked_list.rs20
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs30
-rw-r--r--library/alloc/src/collections/vec_deque/spec_extend.rs13
-rw-r--r--library/alloc/src/fmt.rs4
-rw-r--r--library/alloc/src/lib.rs3
-rw-r--r--library/alloc/src/macros.rs12
-rw-r--r--library/alloc/src/raw_vec.rs17
-rw-r--r--library/alloc/src/sync.rs8
-rw-r--r--library/alloc/src/vec/mod.rs21
-rw-r--r--library/alloc/tests/fmt.rs10
-rw-r--r--library/core/src/any.rs2
-rw-r--r--library/core/src/clone.rs2
-rw-r--r--library/core/src/default.rs1
-rw-r--r--library/core/src/error.rs7
-rw-r--r--library/core/src/ffi/mod.rs414
-rw-r--r--library/core/src/ffi/va_list.rs301
-rw-r--r--library/core/src/fmt/mod.rs22
-rw-r--r--library/core/src/hash/sip.rs11
-rw-r--r--library/core/src/hint.rs97
-rw-r--r--library/core/src/intrinsics.rs2
-rw-r--r--library/core/src/intrinsics/simd.rs19
-rw-r--r--library/core/src/iter/adapters/mod.rs2
-rw-r--r--library/core/src/iter/traits/collect.rs122
-rw-r--r--library/core/src/lib.rs3
-rw-r--r--library/core/src/mem/mod.rs14
-rw-r--r--library/core/src/num/dec2flt/lemire.rs2
-rw-r--r--library/core/src/num/f16.rs15
-rw-r--r--library/core/src/panic.rs2
-rw-r--r--library/core/src/panic/panic_info.rs10
-rw-r--r--library/core/src/ptr/const_ptr.rs126
-rw-r--r--library/core/src/ptr/mut_ptr.rs126
-rw-r--r--library/core/src/ptr/non_null.rs131
-rw-r--r--library/core/src/range.rs494
-rw-r--r--library/core/src/range/iter.rs340
-rw-r--r--library/core/src/range/legacy.rs10
-rw-r--r--library/core/src/slice/index.rs124
-rw-r--r--library/core/src/slice/sort/stable/drift.rs2
-rw-r--r--library/core/src/str/traits.rs195
-rw-r--r--library/core/src/sync/atomic.rs3
-rw-r--r--library/core/src/time.rs5
-rw-r--r--library/core/tests/fmt/builders.rs6
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/panic_unwind/src/lib.rs34
-rw-r--r--library/portable-simd/crates/core_simd/src/swizzle_dyn.rs2
-rw-r--r--library/std/build.rs4
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs2
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/os/fd/owned.rs5
-rw-r--r--library/std/src/path.rs107
-rw-r--r--library/std/src/path/tests.rs109
-rw-r--r--library/std/src/sync/once_lock.rs19
-rw-r--r--library/std/src/sys/pal/unix/args.rs2
-rw-r--r--library/std/src/sys/pal/unix/fs.rs4
-rw-r--r--library/std/src/sys/pal/unix/process/process_vxworks.rs2
-rw-r--r--library/std/src/sys/pal/wasm/atomics/futex.rs17
-rw-r--r--library/std/src/sys/pal/wasm/atomics/thread.rs8
-rw-r--r--library/std/src/sys/pal/windows/alloc.rs2
-rw-r--r--library/std/src/sys/pal/windows/c.rs9
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt2
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs970
-rw-r--r--library/std/src/sys/pal/windows/c/windows_targets.rs24
-rw-r--r--library/std/src/sys/pal/windows/stdio.rs8
-rw-r--r--src/bootstrap/Cargo.lock1
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/src/bin/rustc.rs17
-rw-r--r--src/bootstrap/src/core/build_steps/clean.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs92
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs272
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs38
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs56
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs23
-rw-r--r--src/bootstrap/src/core/build_steps/perf.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs19
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/suggest.rs17
-rw-r--r--src/bootstrap/src/core/build_steps/synthetic_targets.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs187
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs19
-rw-r--r--src/bootstrap/src/core/build_steps/toolstate.rs19
-rw-r--r--src/bootstrap/src/core/build_steps/vendor.rs6
-rw-r--r--src/bootstrap/src/core/builder.rs37
-rw-r--r--src/bootstrap/src/core/config/config.rs26
-rw-r--r--src/bootstrap/src/core/download.rs4
-rw-r--r--src/bootstrap/src/core/metadata.rs7
-rw-r--r--src/bootstrap/src/core/sanity.rs16
-rw-r--r--src/bootstrap/src/lib.rs183
-rw-r--r--src/bootstrap/src/utils/cache.rs7
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs8
-rw-r--r--src/bootstrap/src/utils/channel.rs14
-rw-r--r--src/bootstrap/src/utils/exec.rs175
-rw-r--r--src/bootstrap/src/utils/helpers.rs23
-rw-r--r--src/bootstrap/src/utils/tarball.rs32
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh54
-rwxr-xr-xsrc/ci/docker/run.sh3
-rwxr-xr-xsrc/ci/docker/scripts/fuchsia-test-runner.py63
-rwxr-xr-xsrc/ci/github-actions/calculate-job-matrix.py14
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md2
-rw-r--r--src/doc/rustdoc/src/advanced-features.md3
-rw-r--r--src/doc/style-guide/src/nightly.md12
-rw-r--r--src/doc/unstable-book/src/compiler-flags/verbose-asm.md70
-rw-r--r--src/etc/natvis/intrinsic.natvis26
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/librustdoc/clean/types.rs4
-rw-r--r--src/librustdoc/html/markdown.rs111
-rw-r--r--src/librustdoc/html/render/write_shared.rs3
-rw-r--r--src/librustdoc/html/static/js/search.js18
-rw-r--r--src/librustdoc/json/conversions.rs11
-rw-r--r--src/librustdoc/lint.rs9
-rw-r--r--src/librustdoc/passes/lint.rs2
-rw-r--r--src/librustdoc/passes/lint/bare_urls.rs40
-rw-r--r--src/librustdoc/passes/lint/html_tags.rs6
-rw-r--r--src/librustdoc/passes/lint/redundant_explicit_links.rs16
-rw-r--r--src/librustdoc/passes/lint/unportable_markdown.rs152
m---------src/llvm-project0
-rw-r--r--src/rustdoc-json-types/lib.rs6
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_with_brackets.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs2
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr2
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr1
-rw-r--r--src/tools/clippy/tests/ui/manual_split_once.stderr10
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed2
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr8
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.stderr2
-rw-r--r--src/tools/generate-windows-sys/Cargo.toml2
-rw-r--r--src/tools/generate-windows-sys/src/main.rs1
-rw-r--r--src/tools/jsondocck/src/cache.rs2
-rw-r--r--src/tools/jsondocck/src/main.rs4
-rw-r--r--src/tools/jsondoclint/src/validator.rs4
-rw-r--r--src/tools/linkchecker/main.rs2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs10
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs19
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs4
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs41
-rw-r--r--src/tools/miri/src/eval.rs2
-rw-r--r--src/tools/miri/src/helpers.rs10
-rw-r--r--src/tools/miri/src/machine.rs6
-rw-r--r--src/tools/miri/src/shims/backtrace.rs2
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs15
-rw-r--r--src/tools/miri/src/shims/panic.rs6
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs41
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs13
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs16
-rw-r--r--src/tools/miri/src/shims/x86/avx.rs11
-rw-r--r--src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs10
-rw-r--r--src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr25
-rw-r--r--src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs17
-rw-r--r--src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr17
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs35
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr27
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs.rs26
-rw-r--r--src/tools/miri/tests/pass/async-closure.rs21
-rw-r--r--src/tools/miri/tests/pass/async-closure.stdout6
-rw-r--r--src/tools/miri/tests/pass/function_pointers.rs3
-rw-r--r--src/tools/miri/tests/pass/intptrcast.rs4
-rw-r--r--src/tools/miri/tests/pass/issues/issue-91636.rs1
-rw-r--r--src/tools/miri/tests/pass/packed_struct.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs4
-rw-r--r--src/tools/miri/tests/pass/shims/io.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs5
-rw-r--r--src/tools/miri/tests/pass/tail_call.rs39
-rw-r--r--src/tools/miri/tests/pass/vecdeque.rs4
-rw-r--r--src/tools/remote-test-client/src/main.rs2
-rw-r--r--src/tools/run-make-support/src/command.rs13
-rw-r--r--src/tools/run-make-support/src/diff/mod.rs34
-rw-r--r--src/tools/run-make-support/src/fs_wrapper.rs20
-rw-r--r--src/tools/run-make-support/src/lib.rs76
-rw-r--r--src/tools/run-make-support/src/llvm.rs7
-rw-r--r--src/tools/run-make-support/src/rustc.rs27
-rw-r--r--src/tools/run-make-support/src/rustdoc.rs3
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs8
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/anymap.rs71
-rw-r--r--src/tools/rust-installer/src/combiner.rs9
-rw-r--r--src/tools/rust-installer/src/generator.rs9
-rw-r--r--src/tools/rust-installer/src/tarballer.rs18
-rw-r--r--src/tools/rustfmt/src/types.rs34
-rw-r--r--src/tools/rustfmt/tests/target/return-type-notation.rs10
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt34
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--src/tools/tidy/src/features.rs14
-rw-r--r--src/tools/tidy/src/pal.rs2
-rw-r--r--src/tools/tidy/src/run_make_tests.rs2
-rw-r--r--src/tools/tidy/src/style.rs3
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/assembly/asm-comments.rs12
-rw-r--r--tests/codegen-units/item-collection/drop_in_place_intrinsic.rs1
-rw-r--r--tests/codegen/cast-target-abi.rs367
-rw-r--r--tests/codegen/cffi/ffi-out-of-bounds-loads.rs4
-rw-r--r--tests/coverage-run-rustdoc/doctest.coverage8
-rw-r--r--tests/coverage/async.cov-map41
-rw-r--r--tests/coverage/async.coverage20
-rw-r--r--tests/coverage/async.rs10
-rw-r--r--tests/coverage/attr/nested.cov-map8
-rw-r--r--tests/coverage/attr/nested.coverage5
-rw-r--r--tests/coverage/attr/nested.rs5
-rw-r--r--tests/coverage/attr/off-on-sandwich.cov-map21
-rw-r--r--tests/coverage/attr/off-on-sandwich.coverage21
-rw-r--r--tests/coverage/attr/off-on-sandwich.rs5
-rw-r--r--tests/coverage/closure_macro.cov-map5
-rw-r--r--tests/coverage/closure_macro_async.cov-map5
-rw-r--r--tests/coverage/holes.cov-map47
-rw-r--r--tests/coverage/holes.coverage68
-rw-r--r--tests/coverage/holes.rs67
-rw-r--r--tests/coverage/mcdc/if.cov-map (renamed from tests/coverage/mcdc_if.cov-map)14
-rw-r--r--tests/coverage/mcdc/if.coverage (renamed from tests/coverage/mcdc_if.coverage)28
-rw-r--r--tests/coverage/mcdc/if.rs (renamed from tests/coverage/mcdc_if.rs)2
-rw-r--r--tests/coverage/mcdc/inlined_expressions.cov-map21
-rw-r--r--tests/coverage/mcdc/inlined_expressions.coverage41
-rw-r--r--tests/coverage/mcdc/inlined_expressions.rs17
-rw-r--r--tests/coverage/mcdc/nested_if.cov-map (renamed from tests/coverage/mcdc_nested_if.cov-map)8
-rw-r--r--tests/coverage/mcdc/nested_if.coverage (renamed from tests/coverage/mcdc_nested_if.coverage)25
-rw-r--r--tests/coverage/mcdc/nested_if.rs (renamed from tests/coverage/mcdc_nested_if.rs)2
-rw-r--r--tests/coverage/mcdc/non_control_flow.cov-map (renamed from tests/coverage/mcdc_non_control_flow.cov-map)14
-rw-r--r--tests/coverage/mcdc/non_control_flow.coverage (renamed from tests/coverage/mcdc_non_control_flow.coverage)25
-rw-r--r--tests/coverage/mcdc/non_control_flow.rs (renamed from tests/coverage/mcdc_non_control_flow.rs)2
-rw-r--r--tests/coverage/no_cov_crate.cov-map14
-rw-r--r--tests/coverage/no_cov_crate.coverage20
-rw-r--r--tests/crashes/125099.rs24
-rw-r--r--tests/crashes/125249.rs2
-rw-r--r--tests/crashes/126896.rs17
-rw-r--r--tests/crashes/126939.rs21
-rw-r--r--tests/crashes/126942.rs11
-rw-r--r--tests/crashes/126944.rs38
-rw-r--r--tests/crashes/126966.rs29
-rw-r--r--tests/crashes/126969.rs9
-rw-r--r--tests/crashes/126982.rs18
-rw-r--r--tests/crashes/127222.rs3
-rw-r--r--tests/crashes/127266.rs17
-rw-r--r--tests/crashes/127299.rs12
-rw-r--r--tests/crashes/127304.rs20
-rw-r--r--tests/debuginfo/basic-types-globals-metadata.rs7
-rw-r--r--tests/debuginfo/basic-types-globals.rs11
-rw-r--r--tests/debuginfo/basic-types-metadata.rs4
-rw-r--r--tests/debuginfo/basic-types-mut-globals.rs44
-rw-r--r--tests/debuginfo/basic-types.rs14
-rw-r--r--tests/debuginfo/borrowed-basic.rs15
-rw-r--r--tests/debuginfo/borrowed-unique-basic.rs15
-rw-r--r--tests/debuginfo/f16-natvis.rs58
-rw-r--r--tests/debuginfo/reference-debuginfo.rs17
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir2
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir2
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir6
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir6
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir47
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir47
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-abort.mir10
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir10
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir6
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir6
-rw-r--r--tests/mir-opt/async_closure_shims.rs20
-rw-r--r--tests/mir-opt/building/match/simple_match.match_enum.built.after.mir60
-rw-r--r--tests/mir-opt/building/match/simple_match.rs14
-rw-r--r--tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_direct.Inline.after.panic-abort.mir22
-rw-r--r--tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_direct.Inline.after.panic-unwind.mir22
-rw-r--r--tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_indirect.Inline.after.panic-abort.mir27
-rw-r--r--tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_indirect.Inline.after.panic-unwind.mir27
-rw-r--r--tests/mir-opt/inline/inline_more_in_non_inline.monomorphic_not_inline.Inline.after.panic-abort.mir34
-rw-r--r--tests/mir-opt/inline/inline_more_in_non_inline.monomorphic_not_inline.Inline.after.panic-unwind.mir34
-rw-r--r--tests/mir-opt/inline/inline_more_in_non_inline.rs46
-rw-r--r--tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff58
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir231
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir237
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir195
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir195
-rw-r--r--tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-abort.diff108
-rw-r--r--tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-unwind.diff109
-rw-r--r--tests/mir-opt/tail_call_drops.f.built.after.panic-abort.mir118
-rw-r--r--tests/mir-opt/tail_call_drops.f.built.after.panic-unwind.mir118
-rw-r--r--tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-abort.diff184
-rw-r--r--tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-unwind.diff184
-rw-r--r--tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-abort.mir202
-rw-r--r--tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-unwind.mir202
-rw-r--r--tests/mir-opt/tail_call_drops.rs41
-rw-r--r--tests/pretty/issue-4264.pp21
-rw-r--r--tests/run-make/comment-section/rmake.rs2
-rw-r--r--tests/run-make/compressed-debuginfo/rmake.rs9
-rw-r--r--tests/run-make/dylib-chain/Makefile13
-rw-r--r--tests/run-make/dylib-chain/rmake.rs23
-rw-r--r--tests/run-make/dylib-soname/foo.rs1
-rw-r--r--tests/run-make/dylib-soname/rmake.rs19
-rw-r--r--tests/run-make/emit-named-files/rmake.rs2
-rw-r--r--tests/run-make/emit-path-unhashed/Makefile37
-rw-r--r--tests/run-make/emit-path-unhashed/rmake.rs34
-rw-r--r--tests/run-make/emit-shared-files/Makefile46
-rw-r--r--tests/run-make/emit-shared-files/rmake.rs102
-rw-r--r--tests/run-make/inaccessible-temp-dir/rmake.rs8
-rw-r--r--tests/run-make/include-all-symbols-linking/lib.rs (renamed from tests/run-make/issue-47384/lib.rs)0
-rw-r--r--tests/run-make/include-all-symbols-linking/linker.ld (renamed from tests/run-make/issue-47384/linker.ld)0
-rw-r--r--tests/run-make/include-all-symbols-linking/main.rs (renamed from tests/run-make/issue-47384/main.rs)0
-rw-r--r--tests/run-make/include-all-symbols-linking/rmake.rs31
-rw-r--r--tests/run-make/include-bytes-deps/input.bin (renamed from tests/run-make/include_bytes_deps/input.bin)0
-rw-r--r--tests/run-make/include-bytes-deps/input.md (renamed from tests/run-make/include_bytes_deps/input.md)0
-rw-r--r--tests/run-make/include-bytes-deps/input.txt (renamed from tests/run-make/include_bytes_deps/input.txt)0
-rw-r--r--tests/run-make/include-bytes-deps/main.rs (renamed from tests/run-make/include_bytes_deps/main.rs)0
-rw-r--r--tests/run-make/include-bytes-deps/rmake.rs13
-rw-r--r--tests/run-make/include_bytes_deps/Makefile7
-rw-r--r--tests/run-make/intrinsic-unreachable/Makefile12
-rw-r--r--tests/run-make/intrinsic-unreachable/rmake.rs20
-rw-r--r--tests/run-make/issue-37839/Makefile7
-rw-r--r--tests/run-make/issue-40535/Makefile13
-rw-r--r--tests/run-make/issue-47384/Makefile12
-rw-r--r--tests/run-make/llvm-ident/Makefile19
-rw-r--r--tests/run-make/llvm-ident/rmake.rs35
-rw-r--r--tests/run-make/metadata-only-crate-no-ice/bar.rs (renamed from tests/run-make/issue-40535/bar.rs)0
-rw-r--r--tests/run-make/metadata-only-crate-no-ice/baz.rs (renamed from tests/run-make/issue-40535/baz.rs)0
-rw-r--r--tests/run-make/metadata-only-crate-no-ice/foo.rs (renamed from tests/run-make/issue-40535/foo.rs)0
-rw-r--r--tests/run-make/metadata-only-crate-no-ice/rmake.rs14
-rw-r--r--tests/run-make/msvc-opt-minsize/Makefile6
-rw-r--r--tests/run-make/msvc-opt-minsize/foo.rs19
-rw-r--r--tests/run-make/optimization-remarks-dir-pgo/Makefile17
-rw-r--r--tests/run-make/optimization-remarks-dir-pgo/rmake.rs41
-rw-r--r--tests/run-make/optimization-remarks-dir/Makefile12
-rw-r--r--tests/run-make/optimization-remarks-dir/rmake.rs39
-rw-r--r--tests/run-make/output-type-permutations/Makefile147
-rw-r--r--tests/run-make/output-type-permutations/rmake.rs542
-rw-r--r--tests/run-make/pass-linker-flags-flavor/Makefile11
-rw-r--r--tests/run-make/pass-linker-flags-flavor/rmake.rs84
-rw-r--r--tests/run-make/pass-linker-flags-from-dep/Makefile12
-rw-r--r--tests/run-make/pass-linker-flags-from-dep/rmake.rs43
-rw-r--r--tests/run-make/pass-linker-flags/Makefile5
-rw-r--r--tests/run-make/pass-linker-flags/rmake.rs28
-rw-r--r--tests/run-make/pgo-gen/Makefile11
-rw-r--r--tests/run-make/pgo-gen/rmake.rs18
-rw-r--r--tests/run-make/pgo-use/Makefile43
-rw-r--r--tests/run-make/pgo-use/rmake.rs55
-rw-r--r--tests/run-make/proc-macro-three-crates/a.rs (renamed from tests/run-make/issue-37839/a.rs)0
-rw-r--r--tests/run-make/proc-macro-three-crates/b.rs (renamed from tests/run-make/issue-37839/b.rs)0
-rw-r--r--tests/run-make/proc-macro-three-crates/c.rs (renamed from tests/run-make/issue-37839/c.rs)0
-rw-r--r--tests/run-make/proc-macro-three-crates/rmake.rs20
-rw-r--r--tests/run-make/profile/Makefile13
-rw-r--r--tests/run-make/profile/rmake.rs22
-rw-r--r--tests/run-make/rlib-chain/Makefile11
-rw-r--r--tests/run-make/rlib-chain/rmake.rs23
-rw-r--r--tests/run-make/rmeta-preferred/Makefile16
-rw-r--r--tests/run-make/rmeta-preferred/rmake.rs18
-rw-r--r--tests/run-make/rustdoc-io-error/rmake.rs7
-rw-r--r--tests/run-make/sepcomp-cci-copies/Makefile12
-rw-r--r--tests/run-make/sepcomp-cci-copies/rmake.rs17
-rw-r--r--tests/run-make/sepcomp-inlining/Makefile15
-rw-r--r--tests/run-make/sepcomp-inlining/rmake.rs23
-rw-r--r--tests/run-make/sepcomp-separate/Makefile9
-rw-r--r--tests/run-make/sepcomp-separate/rmake.rs15
-rw-r--r--tests/run-make/static-pie/rmake.rs2
-rw-r--r--tests/run-make/target-cpu-native/Makefile20
-rw-r--r--tests/run-make/target-cpu-native/rmake.rs14
-rw-r--r--tests/run-make/target-specs/Makefile12
-rw-r--r--tests/run-make/target-specs/rmake.rs71
-rw-r--r--tests/run-make/target-without-atomic-cas/Makefile5
-rw-r--r--tests/run-make/target-without-atomic-cas/rmake.rs16
-rw-r--r--tests/run-make/test-harness/Makefile9
-rw-r--r--tests/run-make/test-harness/rmake.rs25
-rw-r--r--tests/run-make/track-path-dep-info/Makefile13
-rw-r--r--tests/run-make/track-path-dep-info/rmake.rs13
-rw-r--r--tests/run-make/track-pgo-dep-info/Makefile25
-rw-r--r--tests/run-make/track-pgo-dep-info/rmake.rs23
-rw-r--r--tests/run-make/volatile-intrinsics/Makefile10
-rw-r--r--tests/run-make/volatile-intrinsics/rmake.rs18
-rw-r--r--tests/run-make/wasm-abi/rmake.rs11
-rw-r--r--tests/run-make/wasm-exceptions-nostd/Makefile12
-rw-r--r--tests/run-make/wasm-exceptions-nostd/rmake.rs18
-rw-r--r--tests/run-make/wasm-exceptions-nostd/src/lib.rs1
-rw-r--r--tests/run-make/wasm-exceptions-nostd/src/panicking.rs4
-rw-r--r--tests/run-make/wasm-override-linker/Makefile16
-rw-r--r--tests/run-make/wasm-override-linker/rmake.rs17
-rw-r--r--tests/run-make/weird-output-filenames/Makefile15
-rw-r--r--tests/run-make/weird-output-filenames/rmake.rs19
-rw-r--r--tests/rustdoc-json/lifetime/outlives_in_param.rs8
-rw-r--r--tests/rustdoc-json/lifetime/outlives_in_where.rs24
-rw-r--r--tests/rustdoc-json/trait_alias.rs18
-rw-r--r--tests/rustdoc-json/type_alias.rs15
-rw-r--r--tests/rustdoc-ui/diagnostic-width.stderr6
-rw-r--r--tests/rustdoc-ui/include-str-bare-urls.stderr6
-rw-r--r--tests/rustdoc-ui/lints/bare-urls.stderr102
-rw-r--r--tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr6
-rw-r--r--tests/rustdoc-ui/unportable-markdown.rs63
-rw-r--r--tests/rustdoc-ui/unportable-markdown.stderr39
-rw-r--r--tests/ui-fulldeps/deriving-global.rs3
-rw-r--r--tests/ui-fulldeps/deriving-hygiene.rs1
-rw-r--r--tests/ui-fulldeps/run-compiler-twice.rs7
-rw-r--r--tests/ui/abi/compatibility.rs5
-rw-r--r--tests/ui/argument-suggestions/basic.stderr10
-rw-r--r--tests/ui/argument-suggestions/exotic-calls.stderr40
-rw-r--r--tests/ui/argument-suggestions/extra_arguments.stderr169
-rw-r--r--tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs21
-rw-r--r--tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr136
-rw-r--r--tests/ui/assign-imm-local-twice.rs2
-rw-r--r--tests/ui/assign-imm-local-twice.stderr8
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs4
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr12
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/bare-path.rs26
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr66
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/basic.rs2
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/equality.rs2
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/equality.stderr4
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs2
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr4
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/missing.rs2
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/missing.stderr2
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs2
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr4
-rw-r--r--tests/ui/associated-types/associated-types-eq-expr-path.rs5
-rw-r--r--tests/ui/associated-types/associated-types-eq-expr-path.stderr22
-rw-r--r--tests/ui/associated-types/defaults-specialization.stderr18
-rw-r--r--tests/ui/associated-types/issue-22560.stderr12
-rw-r--r--tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs2
-rw-r--r--tests/ui/async-await/async-closures/force-move-due-to-actually-fnonce.rs2
-rw-r--r--tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs2
-rw-r--r--tests/ui/async-await/async-closures/implements-fnmut.rs10
-rw-r--r--tests/ui/async-await/async-closures/signature-deduction.rs2
-rw-r--r--tests/ui/async-await/async-closures/signature-inference-from-two-part-bound.rs27
-rw-r--r--tests/ui/async-await/in-trait/async-generics-and-bounds.stderr12
-rw-r--r--tests/ui/async-await/in-trait/async-generics.stderr12
-rw-r--r--tests/ui/async-await/issue-61452.stderr10
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-early.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-late.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr12
-rw-r--r--tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr4
-rw-r--r--tests/ui/async-await/return-type-notation/super-method-bound.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/supertrait-bound.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/ty-or-ct-params.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr10
-rw-r--r--tests/ui/borrowck/alias-liveness/rtn-static.rs4
-rw-r--r--tests/ui/borrowck/borrow-raw-address-of-mutability.stderr8
-rw-r--r--tests/ui/borrowck/borrowck-closures-unique.stderr7
-rw-r--r--tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr20
-rw-r--r--tests/ui/borrowck/immutable-arg.stderr7
-rw-r--r--tests/ui/borrowck/issue-111554.stderr7
-rw-r--r--tests/ui/borrowck/issue-33819.stderr11
-rw-r--r--tests/ui/borrowck/issue-45199.rs6
-rw-r--r--tests/ui/borrowck/issue-45199.stderr26
-rw-r--r--tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr48
-rw-r--r--tests/ui/borrowck/mutability-errors.stderr64
-rw-r--r--tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr8
-rw-r--r--tests/ui/borrowck/tainted-promoteds.stderr10
-rw-r--r--tests/ui/cannot-mutate-captured-non-mut-var.stderr14
-rw-r--r--tests/ui/cast/cast-rfc0401-vtable-kinds.rs18
-rw-r--r--tests/ui/cast/cast-rfc0401-vtable-kinds.stderr2
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-add-auto.rs18
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-add-auto.stderr43
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-add-super-auto.rs9
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-args.rs37
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-args.stderr53
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs27
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr15
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs31
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr10
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs37
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr136
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-ok.rs17
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs14
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr11
-rw-r--r--tests/ui/closures/2229_closure_analysis/array_subslice.stderr8
-rw-r--r--tests/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr16
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs4
-rw-r--r--tests/ui/closures/closure-immutable-outer-variable.stderr7
-rw-r--r--tests/ui/closures/issue-72408-nested-closures-exponential.rs4
-rw-r--r--tests/ui/closures/issue-72408-nested-closures-exponential.stderr10
-rw-r--r--tests/ui/codegen/overflow-during-mono.rs2
-rw-r--r--tests/ui/codegen/overflow-during-mono.stderr11
-rw-r--r--tests/ui/command-line-diagnostics.stderr10
-rw-r--r--tests/ui/compare-method/bad-self-type.stderr20
-rw-r--r--tests/ui/compare-method/issue-90444.stderr18
-rw-r--r--tests/ui/compare-method/reordered-type-param.stderr10
-rw-r--r--tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs18
-rw-r--r--tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr51
-rw-r--r--tests/ui/const-generics/assoc_const_as_type_argument.rs1
-rw-r--r--tests/ui/const-generics/assoc_const_as_type_argument.stderr18
-rw-r--r--tests/ui/const-generics/const-arg-in-const-arg.min.stderr120
-rw-r--r--tests/ui/const-generics/const-arg-in-const-arg.rs4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs14
-rw-r--r--tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr18
-rw-r--r--tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr12
-rw-r--r--tests/ui/const-generics/issues/issue-62878.min.stderr30
-rw-r--r--tests/ui/const-generics/issues/issue-62878.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-86535-2.rs1
-rw-r--r--tests/ui/const-generics/issues/issue-86535.rs1
-rw-r--r--tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs1
-rw-r--r--tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr38
-rw-r--r--tests/ui/const-generics/min_const_generics/macro-fail.rs3
-rw-r--r--tests/ui/const-generics/min_const_generics/macro-fail.stderr61
-rw-r--r--tests/ui/const-generics/suggest_const_for_array.rs2
-rw-r--r--tests/ui/const-generics/suggest_const_for_array.stderr31
-rw-r--r--tests/ui/consts/const-assert-unchecked-ub.rs6
-rw-r--r--tests/ui/consts/const-assert-unchecked-ub.stderr2
-rw-r--r--tests/ui/consts/issue-39974.stderr10
-rw-r--r--tests/ui/consts/offset_from_ub.rs8
-rw-r--r--tests/ui/consts/offset_from_ub.stderr16
-rw-r--r--tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.rs4
-rw-r--r--tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr9
-rw-r--r--tests/ui/deriving/deriving-in-fn.rs2
-rw-r--r--tests/ui/deriving/deriving-smart-pointer-neg.rs45
-rw-r--r--tests/ui/deriving/deriving-smart-pointer-neg.stderr75
-rw-r--r--tests/ui/deriving/deriving-smart-pointer.rs1
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr5
-rw-r--r--tests/ui/did_you_mean/issue-34337.stderr11
-rw-r--r--tests/ui/did_you_mean/issue-37139.stderr11
-rw-r--r--tests/ui/did_you_mean/issue-53280-expected-float-found-integer-literal.stderr33
-rw-r--r--tests/ui/error-codes/E0057.stderr10
-rw-r--r--tests/ui/error-codes/E0308.stderr2
-rw-r--r--tests/ui/error-codes/E0393.stderr6
-rw-r--r--tests/ui/explicit-tail-calls/constck.rs22
-rw-r--r--tests/ui/explicit-tail-calls/constck.stderr19
-rw-r--r--tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.rs14
-rw-r--r--tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr14
-rw-r--r--tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs13
-rw-r--r--tests/ui/explicit-tail-calls/ctfe-arg-move.rs15
-rw-r--r--tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs43
-rw-r--r--tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr36
-rw-r--r--tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs35
-rw-r--r--tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs19
-rw-r--r--tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr21
-rw-r--r--tests/ui/explicit-tail-calls/drop-order.rs70
-rw-r--r--tests/ui/explicit-tail-calls/return-mismatches.rs2
-rw-r--r--tests/ui/explicit-tail-calls/return-mismatches.stderr13
-rw-r--r--tests/ui/explicit-tail-calls/unsafeck.rs11
-rw-r--r--tests/ui/explicit-tail-calls/unsafeck.stderr11
-rw-r--r--tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs1
-rw-r--r--tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-negate-unsigned.stderr9
-rw-r--r--tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr28
-rw-r--r--tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-return_type_notation.rs12
-rw-r--r--tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr22
-rw-r--r--tests/ui/fmt/struct-field-as-captured-argument.fixed14
-rw-r--r--tests/ui/fmt/struct-field-as-captured-argument.rs14
-rw-r--r--tests/ui/fmt/struct-field-as-captured-argument.stderr70
-rw-r--r--tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr4
-rw-r--r--tests/ui/fn/suggest-return-closure.stderr8
-rw-r--r--tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr2
-rw-r--r--tests/ui/generics/generic-function-item-where-type.rs1
-rw-r--r--tests/ui/generics/generic-function-item-where-type.stderr11
-rw-r--r--tests/ui/higher-ranked/well-formed-aliases.rs8
-rw-r--r--tests/ui/higher-ranked/well-formed-aliases.stderr12
-rw-r--r--tests/ui/impl-trait/extra-impl-in-trait-impl.fixed2
-rw-r--r--tests/ui/impl-trait/extra-impl-in-trait-impl.rs2
-rw-r--r--tests/ui/impl-trait/extra-impl-in-trait-impl.stderr8
-rw-r--r--tests/ui/impl-trait/impl-generic-mismatch-ab.stderr10
-rw-r--r--tests/ui/impl-trait/in-assoc-type-unconstrained.stderr11
-rw-r--r--tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr173
-rw-r--r--tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs51
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr10
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr9
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr9
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr9
-rw-r--r--tests/ui/impl-trait/in-trait/specialization-broken.stderr9
-rw-r--r--tests/ui/impl-trait/nested_impl_trait.rs4
-rw-r--r--tests/ui/impl-trait/nested_impl_trait.stderr4
-rw-r--r--tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr20
-rw-r--r--tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr18
-rw-r--r--tests/ui/impl-trait/trait_type.stderr11
-rw-r--r--tests/ui/impl-trait/where-allowed.stderr9
-rw-r--r--tests/ui/imports/suggest-import-issue-120074.rs11
-rw-r--r--tests/ui/imports/suggest-import-issue-120074.stderr23
-rw-r--r--tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr10
-rw-r--r--tests/ui/intrinsics/not-overridden.rs2
-rw-r--r--tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr52
-rw-r--r--tests/ui/intrinsics/safe-intrinsic-mismatch.rs7
-rw-r--r--tests/ui/intrinsics/safe-intrinsic-mismatch.stock.stderr (renamed from tests/ui/intrinsics/safe-intrinsic-mismatch.stderr)12
-rw-r--r--tests/ui/issues/issue-11004.stderr20
-rw-r--r--tests/ui/issues/issue-16939.stderr10
-rw-r--r--tests/ui/issues/issue-20225.stderr27
-rw-r--r--tests/ui/issues/issue-20676.rs2
-rw-r--r--tests/ui/issues/issue-21332.stderr9
-rw-r--r--tests/ui/issues/issue-21950.stderr6
-rw-r--r--tests/ui/issues/issue-22370.stderr6
-rw-r--r--tests/ui/issues/issue-22638.rs5
-rw-r--r--tests/ui/issues/issue-22638.stderr17
-rw-r--r--tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs4
-rw-r--r--tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr10
-rw-r--r--tests/ui/issues/issue-4935.stderr10
-rw-r--r--tests/ui/iterators/issue-58952-filter-type-length.rs8
-rw-r--r--tests/ui/iterators/issue-58952-filter-type-length.stderr8
-rw-r--r--tests/ui/iterators/iter-map-fold-type-length.rs2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_ret.stderr2
-rw-r--r--tests/ui/let-else/let-else-slicing-error.stderr9
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr7
-rw-r--r--tests/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr32
-rw-r--r--tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs7
-rw-r--r--tests/ui/lint/dead-code/issue-59003.rs2
-rw-r--r--tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs37
-rw-r--r--tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr20
-rw-r--r--tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs32
-rw-r--r--tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs36
-rw-r--r--tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr24
-rw-r--r--tests/ui/lint/dead-code/unused-struct-derive-default.rs1
-rw-r--r--tests/ui/lint/dead-code/unused-struct-derive-default.stderr1
-rw-r--r--tests/ui/lint/lint-unconditional-recursion-tail-calls.rs24
-rw-r--r--tests/ui/lint/lint-unconditional-recursion-tail-calls.stderr18
-rw-r--r--tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs2
-rw-r--r--tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr8
-rw-r--r--tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs2
-rw-r--r--tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr8
-rw-r--r--tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs2
-rw-r--r--tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr10
-rw-r--r--tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs2
-rw-r--r--tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr10
-rw-r--r--tests/ui/macros/expr_2021_cargo_fix_edition.fixed24
-rw-r--r--tests/ui/macros/expr_2021_cargo_fix_edition.rs24
-rw-r--r--tests/ui/macros/expr_2021_cargo_fix_edition.stderr33
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2021.stderr4
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2024.stderr2
-rw-r--r--tests/ui/macros/expr_2021_inline_const.rs7
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs12
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs6
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr6
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs78
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr107
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs14
-rw-r--r--tests/ui/macros/out-of-scope-calls-false-positives.rs10
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr2
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs1
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr20
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs36
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs37
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr)20
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs35
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr169
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr (renamed from tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr)75
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs40
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr180
-rw-r--r--tests/ui/method-output-diff-issue-127263.rs8
-rw-r--r--tests/ui/method-output-diff-issue-127263.stderr25
-rw-r--r--tests/ui/methods/method-call-err-msg.stderr10
-rw-r--r--tests/ui/mir/alignment/misaligned-constant-gvn.rs8
-rw-r--r--tests/ui/mismatched_types/E0053.stderr18
-rw-r--r--tests/ui/mismatched_types/cast-rfc0401.rs2
-rw-r--r--tests/ui/mismatched_types/float-literal-inference-restrictions.stderr11
-rw-r--r--tests/ui/mismatched_types/issue-112036.stderr9
-rw-r--r--tests/ui/mismatched_types/issue-13033.stderr9
-rw-r--r--tests/ui/mismatched_types/trait-impl-fn-incompatibility.stderr18
-rw-r--r--tests/ui/msvc-opt-minsize.rs31
-rw-r--r--tests/ui/mut/mut-pattern-internal-mutability.stderr4
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr (renamed from tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr)20
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr116
-rw-r--r--tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs46
-rw-r--r--tests/ui/nll/closure-captures.stderr48
-rw-r--r--tests/ui/nll/coroutine-upvar-mutability.stderr8
-rw-r--r--tests/ui/nll/issue-46023.stderr8
-rw-r--r--tests/ui/panic-handler/panic-handler-bad-signature-1.stderr2
-rw-r--r--tests/ui/parser/bad-let-else-statement.rs16
-rw-r--r--tests/ui/parser/bad-let-else-statement.stderr15
-rw-r--r--tests/ui/parser/issues/issue-105366.fixed1
-rw-r--r--tests/ui/parser/issues/issue-105366.rs1
-rw-r--r--tests/ui/parser/issues/issue-105366.stderr2
-rw-r--r--tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr4
-rw-r--r--tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr8
-rw-r--r--tests/ui/pattern/mut-ref-mut-2021.stderr4
-rw-r--r--tests/ui/pattern/patkind-ref-binding-issue-114896.stderr7
-rw-r--r--tests/ui/pattern/patkind-ref-binding-issue-122415.stderr7
-rw-r--r--tests/ui/range/issue-54505-no-std.stderr6
-rw-r--r--tests/ui/recursion/issue-83150.rs5
-rw-r--r--tests/ui/recursion/issue-83150.stderr16
-rw-r--r--tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr288
-rw-r--r--tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr288
-rw-r--r--tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr288
-rw-r--r--tests/ui/repr/repr-c-dead-variants.rs63
-rw-r--r--tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr288
-rw-r--r--tests/ui/repr/repr-c-int-dead-variants.rs38
-rw-r--r--tests/ui/repr/repr-c-int-dead-variants.stderr288
-rw-r--r--tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr4
-rw-r--r--tests/ui/resolve/issue-2356.stderr4
-rw-r--r--tests/ui/resolve/issue-60057.stderr2
-rw-r--r--tests/ui/resolve/resolve-primitive-fallback.stderr10
-rw-r--r--tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr4
-rw-r--r--tests/ui/resolve/unresolved_static_type_field.stderr2
-rw-r--r--tests/ui/return/tail-expr-as-potential-return.rs36
-rw-r--r--tests/ui/return/tail-expr-as-potential-return.stderr33
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs42
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr24
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr9
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr9
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr9
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr9
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr8
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs8
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr8
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr8
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs7
-rw-r--r--tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr8
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs-ice.rs29
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs-ice.stderr46
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs.default.stderr1
-rw-r--r--tests/ui/simd/simd-bitmask-notpow2.rs90
-rw-r--r--tests/ui/simd/simd-bitmask.rs45
-rw-r--r--tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr4
-rw-r--r--tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr4
-rw-r--r--tests/ui/sized/stack-overflow-trait-infer-98842.rs3
-rw-r--r--tests/ui/span/issue-34264.stderr20
-rw-r--r--tests/ui/structs/structure-constructor-type-mismatch.stderr80
-rw-r--r--tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.fixed4
-rw-r--r--tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs4
-rw-r--r--tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.stderr10
-rw-r--r--tests/ui/suggestions/match-ergonomics.stderr14
-rw-r--r--tests/ui/suggestions/parenthesized-deref-suggestion.stderr14
-rw-r--r--tests/ui/suggestions/pattern-slice-vec.stderr44
-rw-r--r--tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr9
-rw-r--r--tests/ui/test-attrs/test-panic-abort-nocapture.rs1
-rw-r--r--tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr4
-rw-r--r--tests/ui/test-attrs/test-panic-abort.rs1
-rw-r--r--tests/ui/test-attrs/test-panic-abort.run.stdout2
-rw-r--r--tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs2
-rw-r--r--tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr22
-rw-r--r--tests/ui/traits/impl-method-mismatch.stderr2
-rw-r--r--tests/ui/traits/issue-35869.stderr36
-rw-r--r--tests/ui/traits/issue-91949-hangs-on-recursion.rs6
-rw-r--r--tests/ui/traits/issue-91949-hangs-on-recursion.stderr20
-rw-r--r--tests/ui/traits/next-solver/async.fail.stderr6
-rw-r--r--tests/ui/traits/next-solver/async.rs2
-rw-r--r--tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr4
-rw-r--r--tests/ui/traits/next-solver/more-object-bound.stderr15
-rw-r--r--tests/ui/traits/next-solver/typeck/receiver-self-ty-check-eq.rs23
-rw-r--r--tests/ui/traits/upcast_soundness_bug.rs8
-rw-r--r--tests/ui/traits/upcast_soundness_bug.stderr13
-rw-r--r--tests/ui/traits/wrong-mul-method-signature.stderr27
-rw-r--r--tests/ui/try-block/try-block-type-error.stderr10
-rw-r--r--tests/ui/tuple/wrong_argument_ice-4.stderr13
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution3.current.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution3.next.stderr18
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution3.rs6
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution4.current.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution4.next.stderr18
-rw-r--r--tests/ui/type-alias-impl-trait/method_resolution4.rs6
-rw-r--r--tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs29
-rw-r--r--tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr13
-rw-r--r--tests/ui/type-alias-impl-trait/unnameable_type.stderr9
-rw-r--r--tests/ui/type/subtyping-opaque-type.rs19
-rw-r--r--tests/ui/type/type-ascription-instead-of-initializer.stderr10
-rw-r--r--tests/ui/type/type-parameter-defaults-referencing-Self.stderr6
-rw-r--r--tests/ui/type_length_limit.rs4
-rw-r--r--tests/ui/type_length_limit.stderr13
-rw-r--r--tests/ui/typeck/ice-with-expr-not-struct-127332.rs15
-rw-r--r--tests/ui/typeck/ice-with-expr-not-struct-127332.stderr9
-rw-r--r--tests/ui/typeck/issue-53712.rs2
-rw-r--r--tests/ui/typeck/issue-53712.stderr10
-rw-r--r--tests/ui/typeck/issue-91328.stderr32
-rw-r--r--tests/ui/typeck/mismatched-map-under-self.stderr9
-rw-r--r--tests/ui/typeck/ptr-null-mutability-suggestions.stderr10
-rw-r--r--tests/ui/typeck/remove-extra-argument.stderr10
-rw-r--r--tests/ui/typeck/struct-enum-wrong-args.stderr30
-rw-r--r--tests/ui/ufcs/ufcs-explicit-self-bad.stderr9
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr63
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr7
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr24
-rw-r--r--tests/ui/unpretty/expanded-interpolation.rs20
-rw-r--r--tests/ui/unpretty/expanded-interpolation.stdout13
-rw-r--r--tests/ui/unsafe/unsafe-fn-autoderef.stderr10
-rw-r--r--tests/ui/unsigned-literal-negation.stderr27
-rw-r--r--triagebot.toml1
1117 files changed, 24691 insertions, 13855 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 94d70a020a4..afeb9faec09 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3141,7 +3141,19 @@ dependencies = [
  "bitflags 2.5.0",
  "getopts",
  "memchr",
- "pulldown-cmark-escape",
+ "pulldown-cmark-escape 0.10.1",
+ "unicase",
+]
+
+[[package]]
+name = "pulldown-cmark"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8746739f11d39ce5ad5c2520a9b75285310dbfe78c541ccf832d38615765aec0"
+dependencies = [
+ "bitflags 2.5.0",
+ "memchr",
+ "pulldown-cmark-escape 0.11.0",
  "unicase",
 ]
 
@@ -3152,6 +3164,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3"
 
 [[package]]
+name = "pulldown-cmark-escape"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
+
+[[package]]
 name = "pulldown-cmark-to-cmark"
 version = "13.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4150,8 +4168,10 @@ dependencies = [
  "rustc_index",
  "rustc_macros",
  "rustc_middle",
+ "rustc_next_trait_solver",
  "rustc_span",
  "rustc_target",
+ "rustc_type_ir",
  "smallvec",
  "tracing",
 ]
@@ -4604,7 +4624,7 @@ name = "rustc_resolve"
 version = "0.0.0"
 dependencies = [
  "bitflags 2.5.0",
- "pulldown-cmark 0.9.6",
+ "pulldown-cmark 0.11.0",
  "rustc_arena",
  "rustc_ast",
  "rustc_ast_pretty",
@@ -4883,6 +4903,7 @@ dependencies = [
  "indexmap",
  "itertools",
  "minifier",
+ "pulldown-cmark 0.9.6",
  "regex",
  "rustdoc-json-types",
  "serde",
@@ -6337,9 +6358,9 @@ dependencies = [
 
 [[package]]
 name = "windows-bindgen"
-version = "0.57.0"
+version = "0.58.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ccb96113d6277ba543c0f77e1c5494af8094bf9daf9b85acdc3f1b620e7c7b4"
+checksum = "91cd28d93c692351f3a6e5615567c56756e330bee1c99c6bdd57bfc5ab15f589"
 dependencies = [
  "proc-macro2",
  "rayon",
@@ -6360,9 +6381,9 @@ dependencies = [
 
 [[package]]
 name = "windows-metadata"
-version = "0.57.0"
+version = "0.58.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8308d076825b9d9e5abc64f8113e96d02b2aeeba869b20fdd65c7e70cda13dfc"
+checksum = "2e837f3c3012cfe9e7086302a93f441a7999439be1ad4c530d55d2f6d2921809"
 
 [[package]]
 name = "windows-sys"
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 9165b4f2df3..197dd7f9c9e 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -186,7 +186,7 @@ pub trait LayoutCalculator {
         let (present_first, present_second) = {
             let mut present_variants = variants
                 .iter_enumerated()
-                .filter_map(|(i, v)| if absent(v) { None } else { Some(i) });
+                .filter_map(|(i, v)| if !repr.c() && absent(v) { None } else { Some(i) });
             (present_variants.next(), present_variants.next())
         };
         let present_first = match present_first {
@@ -621,7 +621,7 @@ where
     let discr_type = repr.discr_type();
     let bits = Integer::from_attr(dl, discr_type).size().bits();
     for (i, mut val) in discriminants {
-        if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
+        if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) {
             continue;
         }
         if discr_type.is_signed() {
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 31c66a56bea..78332d66f03 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1429,7 +1429,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
     Single { index: VariantIdx },
 
-    /// Enum-likes with more than one inhabited variant: each variant comes with
+    /// Enum-likes with more than one variant: each variant comes with
     /// a *discriminant* (usually the same as the variant index but the user can
     /// assign explicit discriminant values). That discriminant is encoded
     /// as a *tag* on the machine. The layout of each variant is
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index f5e79c04d78..75c656973f9 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -176,6 +176,8 @@ pub enum GenericArgs {
     AngleBracketed(AngleBracketedArgs),
     /// The `(A, B)` and `C` in `Foo(A, B) -> C`.
     Parenthesized(ParenthesizedArgs),
+    /// `(..)` in return type notation.
+    ParenthesizedElided(Span),
 }
 
 impl GenericArgs {
@@ -187,6 +189,7 @@ impl GenericArgs {
         match self {
             AngleBracketed(data) => data.span,
             Parenthesized(data) => data.span,
+            ParenthesizedElided(span) => *span,
         }
     }
 }
@@ -194,11 +197,11 @@ impl GenericArgs {
 /// Concrete argument in the sequence of generic args.
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum GenericArg {
-    /// `'a` in `Foo<'a>`
+    /// `'a` in `Foo<'a>`.
     Lifetime(Lifetime),
-    /// `Bar` in `Foo<Bar>`
+    /// `Bar` in `Foo<Bar>`.
     Type(P<Ty>),
-    /// `1` in `Foo<1>`
+    /// `1` in `Foo<1>`.
     Const(AnonConst),
 }
 
@@ -352,7 +355,7 @@ pub enum GenericParamKind {
         ty: P<Ty>,
         /// Span of the `const` keyword.
         kw_span: Span,
-        /// Optional default value for the const generic param
+        /// Optional default value for the const generic param.
         default: Option<AnonConst>,
     },
 }
@@ -711,6 +714,7 @@ pub enum ByRef {
 }
 
 impl ByRef {
+    #[must_use]
     pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
         if let ByRef::Yes(old_mutbl) = &mut self {
             *old_mutbl = cmp::min(*old_mutbl, mutbl);
@@ -829,7 +833,7 @@ pub enum PatKind {
     /// only one rest pattern may occur in the pattern sequences.
     Rest,
 
-    // A never pattern `!`
+    // A never pattern `!`.
     Never,
 
     /// Parentheses in patterns used for grouping (i.e., `(PAT)`).
@@ -1118,9 +1122,9 @@ impl LocalKind {
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Arm {
     pub attrs: AttrVec,
-    /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`
+    /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`.
     pub pat: P<Pat>,
-    /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`
+    /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`.
     pub guard: Option<P<Expr>>,
     /// Match arm body. Omitted if the pattern is a never pattern.
     pub body: Option<P<Expr>>,
@@ -1351,12 +1355,12 @@ pub struct Closure {
     pub fn_arg_span: Span,
 }
 
-/// Limit types of a range (inclusive or exclusive)
+/// Limit types of a range (inclusive or exclusive).
 #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)]
 pub enum RangeLimits {
-    /// Inclusive at the beginning, exclusive at the end
+    /// Inclusive at the beginning, exclusive at the end.
     HalfOpen,
-    /// Inclusive at the beginning and end
+    /// Inclusive at the beginning and end.
     Closed,
 }
 
@@ -1397,9 +1401,9 @@ pub struct StructExpr {
 pub enum ExprKind {
     /// An array (e.g, `[a, b, c, d]`).
     Array(ThinVec<P<Expr>>),
-    /// Allow anonymous constants from an inline `const` block
+    /// Allow anonymous constants from an inline `const` block.
     ConstBlock(AnonConst),
-    /// A function call
+    /// A function call.
     ///
     /// The first field resolves to the function itself,
     /// and the second field is the list of arguments.
@@ -1453,7 +1457,7 @@ pub enum ExprKind {
     /// A block (`'label: { ... }`).
     Block(P<Block>, Option<Label>),
     /// An `async` block (`async move { ... }`),
-    /// or a `gen` block (`gen move { ... }`)
+    /// or a `gen` block (`gen move { ... }`).
     ///
     /// The span is the "decl", which is the header before the body `{ }`
     /// including the `asyng`/`gen` keywords and possibly `move`.
@@ -2051,7 +2055,7 @@ impl UintTy {
 /// * the `A: Bound` in `Trait<A: Bound>`
 /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
 /// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
-/// * the `f(): Bound` in `Trait<f(): Bound>` (feature `return_type_notation`)
+/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct AssocItemConstraint {
     pub id: NodeId,
@@ -2153,9 +2157,9 @@ pub enum TyKind {
     Never,
     /// A tuple (`(A, B, C, D,...)`).
     Tup(ThinVec<P<Ty>>),
-    /// An anonymous struct type i.e. `struct { foo: Type }`
+    /// An anonymous struct type i.e. `struct { foo: Type }`.
     AnonStruct(NodeId, ThinVec<FieldDef>),
-    /// An anonymous union type i.e. `union { bar: Type }`
+    /// An anonymous union type i.e. `union { bar: Type }`.
     AnonUnion(NodeId, ThinVec<FieldDef>),
     /// A path (`module::module::...::Type`), optionally
     /// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
@@ -2229,9 +2233,9 @@ pub enum TraitObjectSyntax {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum PreciseCapturingArg {
-    /// Lifetime parameter
+    /// Lifetime parameter.
     Lifetime(Lifetime),
-    /// Type or const parameter
+    /// Type or const parameter.
     Arg(Path, NodeId),
 }
 
@@ -2525,11 +2529,11 @@ pub enum Safety {
 /// Iterator`.
 #[derive(Copy, Clone, Encodable, Decodable, Debug)]
 pub enum CoroutineKind {
-    /// `async`, which returns an `impl Future`
+    /// `async`, which returns an `impl Future`.
     Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
-    /// `gen`, which returns an `impl Iterator`
+    /// `gen`, which returns an `impl Iterator`.
     Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
-    /// `async gen`, which returns an `impl AsyncIterator`
+    /// `async gen`, which returns an `impl AsyncIterator`.
     AsyncGen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
 }
 
@@ -2746,7 +2750,7 @@ pub struct Variant {
     pub data: VariantData,
     /// Explicit discriminant, e.g., `Foo = 1`.
     pub disr_expr: Option<AnonConst>,
-    /// Is a macro placeholder
+    /// Is a macro placeholder.
     pub is_placeholder: bool,
 }
 
@@ -3020,19 +3024,19 @@ impl Item {
 /// `extern` qualifier on a function item or function type.
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub enum Extern {
-    /// No explicit extern keyword was used
+    /// No explicit extern keyword was used.
     ///
-    /// E.g. `fn foo() {}`
+    /// E.g. `fn foo() {}`.
     None,
-    /// An explicit extern keyword was used, but with implicit ABI
+    /// An explicit extern keyword was used, but with implicit ABI.
     ///
-    /// E.g. `extern fn foo() {}`
+    /// E.g. `extern fn foo() {}`.
     ///
-    /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`)
+    /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`).
     Implicit(Span),
-    /// An explicit extern keyword was used with an explicit ABI
+    /// An explicit extern keyword was used with an explicit ABI.
     ///
-    /// E.g. `extern "C" fn foo() {}`
+    /// E.g. `extern "C" fn foo() {}`.
     Explicit(StrLit, Span),
 }
 
@@ -3051,13 +3055,13 @@ impl Extern {
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub struct FnHeader {
-    /// Whether this is `unsafe`, or has a default safety
+    /// Whether this is `unsafe`, or has a default safety.
     pub safety: Safety,
     /// Whether this is `async`, `gen`, or nothing.
     pub coroutine_kind: Option<CoroutineKind>,
     /// The `const` keyword, if any
     pub constness: Const,
-    /// The `extern` keyword and corresponding ABI string, if any
+    /// The `extern` keyword and corresponding ABI string, if any.
     pub ext: Extern,
 }
 
@@ -3251,7 +3255,7 @@ pub enum ItemKind {
     ///
     /// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
     Trait(Box<Trait>),
-    /// Trait alias
+    /// Trait alias.
     ///
     /// E.g., `trait Foo = Bar + Quux;`.
     TraitAlias(Generics, GenericBounds),
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index 2cf811e9122..7754ca0a0f5 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -10,8 +10,6 @@ use crate::{AssocItem, Expr, ForeignItem, Item, NodeId};
 use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
 use crate::{AttrVec, Attribute, Stmt, StmtKind};
 
-use rustc_span::Span;
-
 use std::fmt;
 use std::marker::PhantomData;
 
@@ -91,37 +89,6 @@ impl<T: AstDeref<Target: HasNodeId>> HasNodeId for T {
     }
 }
 
-/// A trait for AST nodes having a span.
-pub trait HasSpan {
-    fn span(&self) -> Span;
-}
-
-macro_rules! impl_has_span {
-    ($($T:ty),+ $(,)?) => {
-        $(
-            impl HasSpan for $T {
-                fn span(&self) -> Span {
-                    self.span
-                }
-            }
-        )+
-    };
-}
-
-impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility);
-
-impl<T: AstDeref<Target: HasSpan>> HasSpan for T {
-    fn span(&self) -> Span {
-        self.ast_deref().span()
-    }
-}
-
-impl HasSpan for AttrItem {
-    fn span(&self) -> Span {
-        self.span()
-    }
-}
-
 /// A trait for AST nodes having (or not having) collected tokens.
 pub trait HasTokens {
     fn tokens(&self) -> Option<&LazyAttrTokenStream>;
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 593c78df3cd..088ae9ba441 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -202,14 +202,17 @@ impl Attribute {
         }
     }
 
-    pub fn tokens(&self) -> TokenStream {
+    // Named `get_tokens` to distinguish it from the `<Attribute as HasTokens>::tokens` method.
+    pub fn get_tokens(&self) -> TokenStream {
         match &self.kind {
-            AttrKind::Normal(normal) => normal
-                .tokens
-                .as_ref()
-                .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
-                .to_attr_token_stream()
-                .to_tokenstream(),
+            AttrKind::Normal(normal) => TokenStream::new(
+                normal
+                    .tokens
+                    .as_ref()
+                    .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
+                    .to_attr_token_stream()
+                    .to_token_trees(),
+            ),
             &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone(
                 token::DocComment(comment_kind, self.style, data),
                 self.span,
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 7ca950e50e6..846a108091f 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -44,7 +44,7 @@ pub mod tokenstream;
 pub mod visit;
 
 pub use self::ast::*;
-pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens};
+pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 27e781a5a63..cbf21317f1a 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -582,6 +582,7 @@ fn noop_visit_generic_args<T: MutVisitor>(generic_args: &mut GenericArgs, vis: &
     match generic_args {
         GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data),
         GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data),
+        GenericArgs::ParenthesizedElided(span) => vis.visit_span(span),
     }
 }
 
@@ -703,7 +704,7 @@ fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) {
             visit_attr_tts(tts, vis);
             visit_delim_span(dspan, vis);
         }
-        AttrTokenTree::Attributes(AttributesData { attrs, tokens }) => {
+        AttrTokenTree::AttrsTarget(AttrsTarget { attrs, tokens }) => {
             visit_attrs(attrs, vis);
             visit_lazy_tts_opt_mut(Some(tokens), vis);
         }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index b4ddbe20689..ee068f19332 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -14,7 +14,7 @@
 //! ownership of the original.
 
 use crate::ast::{AttrStyle, StmtKind};
-use crate::ast_traits::{HasAttrs, HasSpan, HasTokens};
+use crate::ast_traits::{HasAttrs, HasTokens};
 use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
 use crate::AttrVec;
 
@@ -23,7 +23,6 @@ use rustc_data_structures::sync::{self, Lrc};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_serialize::{Decodable, Encodable};
 use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP};
-use smallvec::{smallvec, SmallVec};
 
 use std::borrow::Cow;
 use std::{cmp, fmt, iter};
@@ -171,8 +170,8 @@ pub enum AttrTokenTree {
     Delimited(DelimSpan, DelimSpacing, Delimiter, AttrTokenStream),
     /// Stores the attributes for an attribute target,
     /// along with the tokens for that attribute target.
-    /// See `AttributesData` for more information
-    Attributes(AttributesData),
+    /// See `AttrsTarget` for more information
+    AttrsTarget(AttrsTarget),
 }
 
 impl AttrTokenStream {
@@ -180,42 +179,33 @@ impl AttrTokenStream {
         AttrTokenStream(Lrc::new(tokens))
     }
 
-    /// Converts this `AttrTokenStream` to a plain `TokenStream`.
-    /// During conversion, `AttrTokenTree::Attributes` get 'flattened'
+    /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`.
+    /// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened'
     /// back to a `TokenStream` of the form `outer_attr attr_target`.
     /// If there are inner attributes, they are inserted into the proper
     /// place in the attribute target tokens.
-    pub fn to_tokenstream(&self) -> TokenStream {
-        let trees: Vec<_> = self
-            .0
-            .iter()
-            .flat_map(|tree| match &tree {
+    pub fn to_token_trees(&self) -> Vec<TokenTree> {
+        let mut res = Vec::with_capacity(self.0.len());
+        for tree in self.0.iter() {
+            match tree {
                 AttrTokenTree::Token(inner, spacing) => {
-                    smallvec![TokenTree::Token(inner.clone(), *spacing)].into_iter()
+                    res.push(TokenTree::Token(inner.clone(), *spacing));
                 }
                 AttrTokenTree::Delimited(span, spacing, delim, stream) => {
-                    smallvec![TokenTree::Delimited(
+                    res.push(TokenTree::Delimited(
                         *span,
                         *spacing,
                         *delim,
-                        stream.to_tokenstream()
-                    ),]
-                    .into_iter()
+                        TokenStream::new(stream.to_token_trees()),
+                    ))
                 }
-                AttrTokenTree::Attributes(data) => {
-                    let idx = data
+                AttrTokenTree::AttrsTarget(target) => {
+                    let idx = target
                         .attrs
                         .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer));
-                    let (outer_attrs, inner_attrs) = data.attrs.split_at(idx);
-
-                    let mut target_tokens: Vec<_> = data
-                        .tokens
-                        .to_attr_token_stream()
-                        .to_tokenstream()
-                        .0
-                        .iter()
-                        .cloned()
-                        .collect();
+                    let (outer_attrs, inner_attrs) = target.attrs.split_at(idx);
+
+                    let mut target_tokens = target.tokens.to_attr_token_stream().to_token_trees();
                     if !inner_attrs.is_empty() {
                         let mut found = false;
                         // Check the last two trees (to account for a trailing semi)
@@ -237,7 +227,7 @@ impl AttrTokenStream {
 
                                 let mut stream = TokenStream::default();
                                 for inner_attr in inner_attrs {
-                                    stream.push_stream(inner_attr.tokens());
+                                    stream.push_stream(inner_attr.get_tokens());
                                 }
                                 stream.push_stream(delim_tokens.clone());
                                 *tree = TokenTree::Delimited(*span, *spacing, *delim, stream);
@@ -251,17 +241,14 @@ impl AttrTokenStream {
                             "Failed to find trailing delimited group in: {target_tokens:?}"
                         );
                     }
-                    let mut flat: SmallVec<[_; 1]> =
-                        SmallVec::with_capacity(target_tokens.len() + outer_attrs.len());
                     for attr in outer_attrs {
-                        flat.extend(attr.tokens().0.iter().cloned());
+                        res.extend(attr.get_tokens().0.iter().cloned());
                     }
-                    flat.extend(target_tokens);
-                    flat.into_iter()
+                    res.extend(target_tokens);
                 }
-            })
-            .collect();
-        TokenStream::new(trees)
+            }
+        }
+        res
     }
 }
 
@@ -275,7 +262,7 @@ impl AttrTokenStream {
 /// have an `attrs` field containing the `#[cfg(FALSE)]` attr,
 /// and a `tokens` field storing the (unparsed) tokens `struct Foo {}`
 #[derive(Clone, Debug, Encodable, Decodable)]
-pub struct AttributesData {
+pub struct AttrsTarget {
     /// Attributes, both outer and inner.
     /// These are stored in the original order that they were parsed in.
     pub attrs: AttrVec,
@@ -409,8 +396,8 @@ impl PartialEq<TokenStream> for TokenStream {
 }
 
 impl TokenStream {
-    pub fn new(streams: Vec<TokenTree>) -> TokenStream {
-        TokenStream(Lrc::new(streams))
+    pub fn new(tts: Vec<TokenTree>) -> TokenStream {
+        TokenStream(Lrc::new(tts))
     }
 
     pub fn is_empty(&self) -> bool {
@@ -449,19 +436,19 @@ impl TokenStream {
         TokenStream::new(vec![TokenTree::token_alone(kind, span)])
     }
 
-    pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream {
+    pub fn from_ast(node: &(impl HasAttrs + HasTokens + fmt::Debug)) -> TokenStream {
         let Some(tokens) = node.tokens() else {
-            panic!("missing tokens for node at {:?}: {:?}", node.span(), node);
+            panic!("missing tokens for node: {:?}", node);
         };
         let attrs = node.attrs();
         let attr_stream = if attrs.is_empty() {
             tokens.to_attr_token_stream()
         } else {
-            let attr_data =
-                AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
-            AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)])
+            let target =
+                AttrsTarget { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
+            AttrTokenStream::new(vec![AttrTokenTree::AttrsTarget(target)])
         };
-        attr_stream.to_tokenstream()
+        TokenStream::new(attr_stream.to_token_trees())
     }
 
     pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
@@ -778,6 +765,7 @@ mod size_asserts {
     static_assert_size!(AttrTokenStream, 8);
     static_assert_size!(AttrTokenTree, 32);
     static_assert_size!(LazyAttrTokenStream, 8);
+    static_assert_size!(Option<LazyAttrTokenStream>, 8); // must be small, used in many AST nodes
     static_assert_size!(TokenStream, 8);
     static_assert_size!(TokenTree, 32);
     // tidy-alphabetical-end
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index 4b2544ac47e..1a80a9ccdbf 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -1,7 +1,8 @@
 //! Routines the parser and pretty-printer use to classify AST nodes.
 
 use crate::ast::ExprKind::*;
-use crate::{ast, token::Delimiter};
+use crate::ast::{self, MatchKind};
+use crate::token::Delimiter;
 
 /// This classification determines whether various syntactic positions break out
 /// of parsing the current expression (true) or continue parsing more of the
@@ -81,6 +82,82 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
     }
 }
 
+/// Returns whether the leftmost token of the given expression is the label of a
+/// labeled loop or block, such as in `'inner: loop { break 'inner 1 } + 1`.
+///
+/// Such expressions are not allowed as the value of an unlabeled break.
+///
+/// ```ignore (illustrative)
+/// 'outer: {
+///     break 'inner: loop { break 'inner 1 } + 1;  // invalid syntax
+///
+///     break 'outer 'inner: loop { break 'inner 1 } + 1;  // okay
+///
+///     break ('inner: loop { break 'inner 1 } + 1);  // okay
+///
+///     break ('inner: loop { break 'inner 1 }) + 1;  // okay
+/// }
+/// ```
+pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
+    loop {
+        match &expr.kind {
+            Block(_, label) | ForLoop { label, .. } | Loop(_, label, _) | While(_, _, label) => {
+                return label.is_some();
+            }
+
+            Assign(e, _, _)
+            | AssignOp(_, e, _)
+            | Await(e, _)
+            | Binary(_, e, _)
+            | Call(e, _)
+            | Cast(e, _)
+            | Field(e, _)
+            | Index(e, _, _)
+            | Match(e, _, MatchKind::Postfix)
+            | Range(Some(e), _, _)
+            | Try(e) => {
+                expr = e;
+            }
+            MethodCall(method_call) => {
+                expr = &method_call.receiver;
+            }
+
+            AddrOf(..)
+            | Array(..)
+            | Become(..)
+            | Break(..)
+            | Closure(..)
+            | ConstBlock(..)
+            | Continue(..)
+            | FormatArgs(..)
+            | Gen(..)
+            | If(..)
+            | IncludedBytes(..)
+            | InlineAsm(..)
+            | Let(..)
+            | Lit(..)
+            | MacCall(..)
+            | Match(_, _, MatchKind::Prefix)
+            | OffsetOf(..)
+            | Paren(..)
+            | Path(..)
+            | Range(None, _, _)
+            | Repeat(..)
+            | Ret(..)
+            | Struct(..)
+            | TryBlock(..)
+            | Tup(..)
+            | Type(..)
+            | Unary(..)
+            | Underscore
+            | Yeet(..)
+            | Yield(..)
+            | Err(..)
+            | Dummy => return false,
+        }
+    }
+}
+
 pub enum TrailingBrace<'a> {
     /// Trailing brace in a macro call, like the one in `x as *const brace! {}`.
     /// We will suggest changing the macro call to a different delimiter.
@@ -234,6 +311,6 @@ fn path_return_type(path: &ast::Path) -> Option<&ast::Ty> {
             ast::FnRetTy::Default(_) => None,
             ast::FnRetTy::Ty(ret) => Some(ret),
         },
-        ast::GenericArgs::AngleBracketed(_) => None,
+        ast::GenericArgs::AngleBracketed(_) | ast::GenericArgs::ParenthesizedElided(_) => None,
     }
 }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 26cb04d4d47..f6929057bed 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -609,6 +609,7 @@ where
             walk_list!(visitor, visit_ty, inputs);
             try_visit!(visitor.visit_fn_ret_ty(output));
         }
+        GenericArgs::ParenthesizedElided(_span) => {}
     }
     V::Result::output()
 }
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 58f65f1257f..9ed93d481e7 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -36,10 +36,15 @@ ast_lowering_bad_return_type_notation_inputs =
     argument types not allowed with return type notation
     .suggestion = remove the input types
 
+ast_lowering_bad_return_type_notation_needs_dots = return type notation arguments must be elided with `..`
+    .suggestion = add `..`
+
 ast_lowering_bad_return_type_notation_output =
     return type not allowed with return type notation
     .suggestion = remove the return type
 
+ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet
+
 ast_lowering_base_expression_double_dot =
     base expression required after `..`
     .suggestion = add a base expression here
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 3d4b6a1f033..4c77892a6b7 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -393,6 +393,17 @@ pub enum BadReturnTypeNotation {
         #[suggestion(code = "", applicability = "maybe-incorrect")]
         span: Span,
     },
+    #[diag(ast_lowering_bad_return_type_notation_needs_dots)]
+    NeedsDots {
+        #[primary_span]
+        #[suggestion(code = "(..)", applicability = "maybe-incorrect")]
+        span: Span,
+    },
+    #[diag(ast_lowering_bad_return_type_notation_position)]
+    Position {
+        #[primary_span]
+        span: Span,
+    },
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index d59ac576629..0ad23b53566 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -625,9 +625,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             _ => Const::No,
                         }
                     } else {
-                        self.tcx
-                            .get_attr(def_id, sym::const_trait)
-                            .map_or(Const::No, |attr| Const::Yes(attr.span))
+                        if self.tcx.is_const_trait(def_id) {
+                            // FIXME(effects) span
+                            Const::Yes(self.tcx.def_ident_span(def_id).unwrap())
+                        } else {
+                            Const::No
+                        }
                     }
                 } else {
                     Const::No
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 8fba46625ab..24748d2d009 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -985,20 +985,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
                 }
                 GenericArgs::Parenthesized(data) => {
-                    if data.inputs.is_empty() && matches!(data.output, FnRetTy::Default(..)) {
-                        let parenthesized = if self.tcx.features().return_type_notation {
-                            hir::GenericArgsParentheses::ReturnTypeNotation
-                        } else {
-                            self.emit_bad_parenthesized_trait_in_assoc_ty(data);
-                            hir::GenericArgsParentheses::No
-                        };
-                        GenericArgsCtor {
-                            args: Default::default(),
-                            constraints: &[],
-                            parenthesized,
-                            span: data.inputs_span,
-                        }
-                    } else if let Some(first_char) = constraint.ident.as_str().chars().next()
+                    if let Some(first_char) = constraint.ident.as_str().chars().next()
                         && first_char.is_ascii_lowercase()
                     {
                         let mut err = if !data.inputs.is_empty() {
@@ -1010,7 +997,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 span: data.inputs_span.shrink_to_hi().to(ty.span),
                             })
                         } else {
-                            unreachable!("inputs are empty and return type is not provided")
+                            self.dcx().create_err(errors::BadReturnTypeNotation::NeedsDots {
+                                span: data.inputs_span,
+                            })
                         };
                         if !self.tcx.features().return_type_notation
                             && self.tcx.sess.is_nightly_build()
@@ -1040,6 +1029,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         .0
                     }
                 }
+                GenericArgs::ParenthesizedElided(span) => GenericArgsCtor {
+                    args: Default::default(),
+                    constraints: &[],
+                    parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
+                    span: *span,
+                },
             };
             gen_args_ctor.into_generic_args(self)
         } else {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 9a1ca703699..6303584bb78 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -1,7 +1,8 @@
 use crate::ImplTraitPosition;
 
 use super::errors::{
-    AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, GenericTypeWithParentheses, UseAngleBrackets,
+    AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation,
+    GenericTypeWithParentheses, UseAngleBrackets,
 };
 use super::ResolverAstLoweringExt;
 use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
@@ -271,6 +272,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         )
                     }
                 },
+                GenericArgs::ParenthesizedElided(span) => {
+                    self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span });
+                    (
+                        GenericArgsCtor {
+                            args: Default::default(),
+                            constraints: &[],
+                            parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
+                            span: *span,
+                        },
+                        false,
+                    )
+                }
             }
         } else {
             (
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 022f953c6e7..dd0d904c52c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1312,6 +1312,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     self.with_impl_trait(None, |this| this.visit_ty(ty));
                 }
             }
+            GenericArgs::ParenthesizedElided(_span) => {}
         }
     }
 
@@ -1468,7 +1469,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                                 span: args.span,
                             });
                         }
-                        None => {}
+                        Some(ast::GenericArgs::ParenthesizedElided(_)) | None => {}
                     }
                 }
             }
@@ -1716,7 +1717,9 @@ fn deny_equality_constraints(
                 // Add `<Bar = RhsTy>` to `Foo`.
                 match &mut assoc_path.segments[len].args {
                     Some(args) => match args.deref_mut() {
-                        GenericArgs::Parenthesized(_) => continue,
+                        GenericArgs::Parenthesized(_) | GenericArgs::ParenthesizedElided(..) => {
+                            continue;
+                        }
                         GenericArgs::AngleBracketed(args) => {
                             args.args.push(arg);
                         }
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index e1c1a027a30..9cf3182daea 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,6 +1,6 @@
 use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_ast::{attr, AssocItemConstraint, AssocItemConstraintKind, NodeId};
+use rustc_ast::{attr, NodeId};
 use rustc_ast::{token, PatKind};
 use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
@@ -445,23 +445,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_fn(self, fn_kind)
     }
 
-    fn visit_assoc_item_constraint(&mut self, constraint: &'a AssocItemConstraint) {
-        if let AssocItemConstraintKind::Bound { .. } = constraint.kind
-            && let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref()
-            && args.inputs.is_empty()
-            && let ast::FnRetTy::Default(..) = args.output
-        {
-            gate!(
-                &self,
-                return_type_notation,
-                constraint.span,
-                "return type notation is experimental"
-            );
-        }
-
-        visit::walk_assoc_item_constraint(self, constraint)
-    }
-
     fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
         let is_fn = match &i.kind {
             ast::AssocItemKind::Fn(_) => true,
@@ -566,6 +549,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
         unsafe_extern_blocks,
         "`unsafe extern {}` blocks and `safe` keyword are experimental"
     );
+    gate_all!(return_type_notation, "return type notation is experimental");
 
     if !visitor.features.never_patterns {
         if let Some(spans) = spans.get(&sym::never_patterns) {
@@ -611,10 +595,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
 
     gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
     gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
-    // Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
-    // used to be gated under associated_type_bounds, which are right above, so RTN needs to
-    // be too.
-    gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
     gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
     gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable");
     gate_all_legacy_dont_use!(auto_traits, "`auto` traits are unstable");
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 0225c95dca8..0568d368d8c 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1060,6 +1060,11 @@ impl<'a> PrintState<'a> for State<'a> {
                 self.word(")");
                 self.print_fn_ret_ty(&data.output);
             }
+            ast::GenericArgs::ParenthesizedElided(_) => {
+                self.word("(");
+                self.word("..");
+                self.word(")");
+            }
         }
     }
 }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 3d1f43a3766..5b13858f839 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -5,6 +5,7 @@ use ast::{ForLoopKind, MatchKind};
 use itertools::{Itertools, Position};
 use rustc_ast::ptr::P;
 use rustc_ast::token;
+use rustc_ast::util::classify;
 use rustc_ast::util::literal::escape_byte_str_symbol;
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
 use rustc_ast::{self as ast, BlockCheckMode};
@@ -610,9 +611,12 @@ impl<'a> State<'a> {
                 }
                 if let Some(expr) = opt_expr {
                     self.space();
-                    self.print_expr_maybe_paren(
+                    self.print_expr_cond_paren(
                         expr,
-                        parser::PREC_JUMP,
+                        // Parenthesize if required by precedence, or in the
+                        // case of `break 'inner: loop { break 'inner 1 } + 1`
+                        expr.precedence().order() < parser::PREC_JUMP
+                            || (opt_label.is_none() && classify::leading_labeled_expr(expr)),
                         fixup.subsequent_subexpression(),
                     );
                 }
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index b54e05b2b34..bb2fc3b67e9 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -1,4 +1,6 @@
+use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker};
 use crate::type_check::Locations;
+use crate::universal_regions::UniversalRegions;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
@@ -48,6 +50,110 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
     ) -> &IndexSlice<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {
         &self.outlives
     }
+
+    /// Computes cycles (SCCs) in the graph of regions. In particular,
+    /// find all regions R1, R2 such that R1: R2 and R2: R1 and group
+    /// them into an SCC, and find the relationships between SCCs.
+    pub(crate) fn compute_sccs(
+        &self,
+        static_region: RegionVid,
+        definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
+    ) -> ConstraintSccs {
+        let constraint_graph = self.graph(definitions.len());
+        let region_graph = &constraint_graph.region_graph(self, static_region);
+        ConstraintSccs::new_with_annotation(&region_graph, |r| {
+            RegionTracker::new(r, &definitions[r])
+        })
+    }
+
+    /// This method handles Universe errors by rewriting the constraint
+    /// graph. For each strongly connected component in the constraint
+    /// graph such that there is a series of constraints
+    ///    A: B: C: ... : X  where
+    /// A's universe is smaller than X's and A is a placeholder,
+    /// add a constraint that A: 'static. This is a safe upper bound
+    /// in the face of borrow checker/trait solver limitations that will
+    /// eventually go away.
+    ///
+    /// For a more precise definition, see the documentation for
+    /// [`RegionTracker::has_incompatible_universes()`].
+    ///
+    /// This edge case used to be handled during constraint propagation
+    /// by iterating over the strongly connected components in the constraint
+    /// graph while maintaining a set of bookkeeping mappings similar
+    /// to what is stored in `RegionTracker` and manually adding 'sttaic as
+    /// needed.
+    ///
+    /// It was rewritten as part of the Polonius project with the goal of moving
+    /// higher-kindedness concerns out of the path of the borrow checker,
+    /// for two reasons:
+    ///
+    /// 1. Implementing Polonius is difficult enough without also
+    ///     handling them.
+    /// 2. The long-term goal is to handle higher-kinded concerns
+    ///     in the trait solver, where they belong. This avoids
+    ///     logic duplication and allows future trait solvers
+    ///     to compute better bounds than for example our
+    ///     "must outlive 'static" here.
+    ///
+    /// This code is a stop-gap measure in preparation for the future trait solver.
+    ///
+    /// Every constraint added by this method is an
+    /// internal `IllegalUniverse` constraint.
+    #[instrument(skip(self, universal_regions, definitions))]
+    pub(crate) fn add_outlives_static(
+        &mut self,
+        universal_regions: &UniversalRegions<'tcx>,
+        definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
+    ) -> ConstraintSccs {
+        let fr_static = universal_regions.fr_static;
+        let sccs = self.compute_sccs(fr_static, definitions);
+
+        // Changed to `true` if we added any constraints to `self` and need to
+        // recompute SCCs.
+        let mut added_constraints = false;
+
+        for scc in sccs.all_sccs() {
+            // No point in adding 'static: 'static!
+            // This micro-optimisation makes somewhat sense
+            // because static outlives *everything*.
+            if scc == sccs.scc(fr_static) {
+                continue;
+            }
+
+            let annotation = sccs.annotation(scc);
+
+            // If this SCC participates in a universe violation,
+            // e.g. if it reaches a region with a universe smaller than
+            // the largest region reached, add a requirement that it must
+            // outlive `'static`.
+            if annotation.has_incompatible_universes() {
+                // Optimisation opportunity: this will add more constraints than
+                // needed for correctness, since an SCC upstream of another with
+                // a universe violation will "infect" its downstream SCCs to also
+                // outlive static.
+                added_constraints = true;
+                let scc_representative_outlives_static = OutlivesConstraint {
+                    sup: annotation.representative,
+                    sub: fr_static,
+                    category: ConstraintCategory::IllegalUniverse,
+                    locations: Locations::All(rustc_span::DUMMY_SP),
+                    span: rustc_span::DUMMY_SP,
+                    variance_info: VarianceDiagInfo::None,
+                    from_closure: false,
+                };
+                self.push(scc_representative_outlives_static);
+            }
+        }
+
+        if added_constraints {
+            // We changed the constraint set and so must recompute SCCs.
+            self.compute_sccs(fr_static, definitions)
+        } else {
+            // If we didn't add any back-edges; no more work needs doing
+            sccs
+        }
+    }
 }
 
 impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 44ab762f66e..b1e302e5e27 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -34,11 +34,12 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span, Symbol};
+use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
-use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
 use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
 use std::iter;
+use std::ops::ControlFlow;
 
 use crate::borrow_set::TwoPhaseActivation;
 use crate::borrowck_errors;
@@ -784,20 +785,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         /// binding declaration within every scope we inspect.
         struct Finder {
             hir_id: hir::HirId,
-            found: bool,
         }
         impl<'hir> Visitor<'hir> for Finder {
-            fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) {
+            type Result = ControlFlow<()>;
+            fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) -> Self::Result {
                 if pat.hir_id == self.hir_id {
-                    self.found = true;
+                    return ControlFlow::Break(());
                 }
-                hir::intravisit::walk_pat(self, pat);
+                hir::intravisit::walk_pat(self, pat)
             }
-            fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
+            fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) -> Self::Result {
                 if ex.hir_id == self.hir_id {
-                    self.found = true;
+                    return ControlFlow::Break(());
                 }
-                hir::intravisit::walk_expr(self, ex);
+                hir::intravisit::walk_expr(self, ex)
             }
         }
         // The immediate HIR parent of the moved expression. We'll look for it to be a call.
@@ -822,9 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 _ => continue,
             };
             if let Some(&hir_id) = local_hir_id {
-                let mut finder = Finder { hir_id, found: false };
-                finder.visit_expr(e);
-                if finder.found {
+                if (Finder { hir_id }).visit_expr(e).is_break() {
                     // The current scope includes the declaration of the binding we're accessing, we
                     // can't look up any further for loops.
                     break;
@@ -839,9 +838,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                         hir::Node::Expr(hir::Expr {
                             kind: hir::ExprKind::If(cond, ..), ..
                         }) => {
-                            let mut finder = Finder { hir_id: expr.hir_id, found: false };
-                            finder.visit_expr(cond);
-                            if finder.found {
+                            if (Finder { hir_id: expr.hir_id }).visit_expr(cond).is_break() {
                                 // The expression where the move error happened is in a `while let`
                                 // condition Don't suggest clone as it will likely end in an
                                 // infinite loop.
@@ -1837,7 +1834,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
 
         pub struct Holds<'tcx> {
             ty: Ty<'tcx>,
-            holds: bool,
         }
 
         impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
@@ -1845,7 +1841,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
 
             fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
                 if t == self.ty {
-                    self.holds = true;
+                    return ControlFlow::Break(());
                 }
                 t.super_visit_with(self)
             }
@@ -1863,9 +1859,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 && rcvr_ty == ty
                 && let ty::Ref(_, inner, _) = rcvr_ty.kind()
                 && let inner = inner.peel_refs()
-                && let mut v = (Holds { ty: inner, holds: false })
-                && let _ = v.visit_ty(local_ty)
-                && v.holds
+                && (Holds { ty: inner }).visit_ty(local_ty).is_break()
                 && let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
             {
                 err.span_label(
@@ -3733,7 +3727,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
             if tcx.is_diagnostic_item(sym::deref_method, method_did) {
                 let deref_target =
                     tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
-                        Instance::resolve(tcx, self.param_env, deref_target, method_args)
+                        Instance::try_resolve(tcx, self.param_env, deref_target, method_args)
                             .transpose()
                     });
                 if let Some(Ok(instance)) = deref_target {
@@ -3757,13 +3751,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         assigned_span: Span,
         err_place: Place<'tcx>,
     ) {
-        let (from_arg, local_decl, local_name) = match err_place.as_local() {
-            Some(local) => (
-                self.body.local_kind(local) == LocalKind::Arg,
-                Some(&self.body.local_decls[local]),
-                self.local_names[local],
-            ),
-            None => (false, None, None),
+        let (from_arg, local_decl) = match err_place.as_local() {
+            Some(local) => {
+                (self.body.local_kind(local) == LocalKind::Arg, Some(&self.body.local_decls[local]))
+            }
+            None => (false, None),
         };
 
         // If root local is initialized immediately (everything apart from let
@@ -3795,13 +3787,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
             err.span_label(assigned_span, format!("first assignment to {place_description}"));
         }
         if let Some(decl) = local_decl
-            && let Some(name) = local_name
             && decl.can_be_made_mutable()
         {
-            err.span_suggestion(
-                decl.source_info.span,
+            err.span_suggestion_verbose(
+                decl.source_info.span.shrink_to_lo(),
                 "consider making this binding mutable",
-                format!("mut {name}"),
+                "mut ".to_string(),
                 Applicability::MachineApplicable,
             );
             if !from_arg
@@ -3813,10 +3804,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     }))
                 )
             {
-                err.span_suggestion(
-                    decl.source_info.span,
+                err.span_suggestion_verbose(
+                    decl.source_info.span.shrink_to_lo(),
                     "to modify the original value, take a borrow instead",
-                    format!("ref mut {name}"),
+                    "ref mut ".to_string(),
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -4328,15 +4319,14 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
 }
 
 /// Detect whether one of the provided spans is a statement nested within the top-most visited expr
-struct ReferencedStatementsVisitor<'a>(&'a [Span], bool);
+struct ReferencedStatementsVisitor<'a>(&'a [Span]);
 
-impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> {
-    fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
+impl<'v> Visitor<'v> for ReferencedStatementsVisitor<'_> {
+    type Result = ControlFlow<()>;
+    fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result {
         match s.kind {
-            hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => {
-                self.1 = true;
-            }
-            _ => {}
+            hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => ControlFlow::Break(()),
+            _ => ControlFlow::Continue(()),
         }
     }
 }
@@ -4378,9 +4368,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
             hir::ExprKind::If(cond, body, None) => {
                 // `if` expressions with no `else` that initialize the binding might be missing an
                 // `else` arm.
-                let mut v = ReferencedStatementsVisitor(self.spans, false);
-                v.visit_expr(body);
-                if v.1 {
+                if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() {
                     self.errors.push((
                         cond.span,
                         format!(
@@ -4397,11 +4385,9 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
             hir::ExprKind::If(cond, body, Some(other)) => {
                 // `if` expressions where the binding is only initialized in one of the two arms
                 // might be missing a binding initialization.
-                let mut a = ReferencedStatementsVisitor(self.spans, false);
-                a.visit_expr(body);
-                let mut b = ReferencedStatementsVisitor(self.spans, false);
-                b.visit_expr(other);
-                match (a.1, b.1) {
+                let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break();
+                let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break();
+                match (a, b) {
                     (true, true) | (false, false) => {}
                     (true, false) => {
                         if other.span.is_desugaring(DesugaringKind::WhileLoop) {
@@ -4440,11 +4426,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> {
                 // arms might be missing an initialization.
                 let results: Vec<bool> = arms
                     .iter()
-                    .map(|arm| {
-                        let mut v = ReferencedStatementsVisitor(self.spans, false);
-                        v.visit_arm(arm);
-                        v.1
-                    })
+                    .map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break())
                     .collect();
                 if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
                     for (arm, seen) in arms.iter().zip(results) {
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 6165a718a30..ffe52f939dd 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{sym, DesugaringKind, Span};
-use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
+use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 
 use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
 use crate::{
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 4567a014fe8..b7fbb71a0cf 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -27,8 +27,8 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Spanned;
 use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, VariantIdx};
+use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{
     type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode,
 };
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index c817a80a541..4b6c1b29f28 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
 use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
 use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
-use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
+use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 
 use crate::diagnostics::CapturedMessageOpt;
 use crate::diagnostics::{DescribePlaceOpt, UseSpans};
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 19a4df0cd7b..26b0d23b166 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -16,9 +16,9 @@ use rustc_middle::{
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{sym, BytePos, DesugaringKind, Span};
 use rustc_target::abi::FieldIdx;
+use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
 
 use crate::diagnostics::BorrowedContentSource;
 use crate::util::FindAssignments;
@@ -408,10 +408,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                                     fn_decl.implicit_self,
                                     hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
                                 ) {
-                                    err.span_suggestion(
-                                        upvar_ident.span,
+                                    err.span_suggestion_verbose(
+                                        upvar_ident.span.shrink_to_lo(),
                                         "consider changing this to be mutable",
-                                        format!("mut {}", upvar_ident.name),
+                                        "mut ",
                                         Applicability::MachineApplicable,
                                     );
                                     break;
@@ -419,10 +419,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                             }
                         }
                     } else {
-                        err.span_suggestion(
-                            upvar_ident.span,
+                        err.span_suggestion_verbose(
+                            upvar_ident.span.shrink_to_lo(),
                             "consider changing this to be mutable",
-                            format!("mut {}", upvar_ident.name),
+                            "mut ",
                             Applicability::MachineApplicable,
                         );
                     }
@@ -449,8 +449,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     .is_ok_and(|snippet| snippet.starts_with("&mut ")) =>
             {
                 err.span_label(span, format!("cannot {act}"));
-                err.span_suggestion(
-                    span,
+                err.span_suggestion_verbose(
+                    span.with_hi(span.lo() + BytePos(5)),
                     "try removing `&mut` here",
                     "",
                     Applicability::MaybeIncorrect,
@@ -755,13 +755,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
                 ..
             }) = node
-            && let Ok(name) =
-                self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
         {
-            err.span_suggestion(
-                pat_span,
+            err.multipart_suggestion(
                 "consider changing this to be mutable",
-                format!("&(mut {name})"),
+                vec![
+                    (pat_span.until(local_decl.source_info.span), "&(mut ".to_string()),
+                    (
+                        local_decl.source_info.span.shrink_to_hi().with_hi(pat_span.hi()),
+                        ")".to_string(),
+                    ),
+                ],
                 Applicability::MachineApplicable,
             );
             return;
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index fba18c38146..55147ee337f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -10,14 +10,12 @@ use rustc_hir::GenericBound::Trait;
 use rustc_hir::QPath::Resolved;
 use rustc_hir::WherePredicate::BoundPredicate;
 use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
-use rustc_infer::infer::{
-    error_reporting::nice_region_error::{
-        self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
-        HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
-    },
-    error_reporting::unexpected_hidden_region_diagnostic,
-    NllRegionVariableOrigin, RelateParamBound,
+use rustc_infer::infer::error_reporting::nice_region_error::{
+    self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
+    HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
 };
+use rustc_infer::infer::error_reporting::region::unexpected_hidden_region_diagnostic;
+use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
 use rustc_middle::bug;
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
@@ -66,7 +64,8 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
             ConstraintCategory::Predicate(_)
             | ConstraintCategory::Boring
             | ConstraintCategory::BoringNoLocation
-            | ConstraintCategory::Internal => "",
+            | ConstraintCategory::Internal
+            | ConstraintCategory::IllegalUniverse => "",
         }
     }
 }
@@ -948,7 +947,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 return;
             }
 
-            if let Ok(Some(instance)) = ty::Instance::resolve(
+            if let Ok(Some(instance)) = ty::Instance::try_resolve(
                 tcx,
                 self.param_env,
                 *fn_did,
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index 51ea59e2092..af96f115385 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -213,8 +213,32 @@ trait FactCell {
     fn to_string(&self, location_table: &LocationTable) -> String;
 }
 
-impl<A: Debug> FactCell for A {
-    default fn to_string(&self, _location_table: &LocationTable) -> String {
+impl FactCell for BorrowIndex {
+    fn to_string(&self, _location_table: &LocationTable) -> String {
+        format!("{self:?}")
+    }
+}
+
+impl FactCell for Local {
+    fn to_string(&self, _location_table: &LocationTable) -> String {
+        format!("{self:?}")
+    }
+}
+
+impl FactCell for MovePathIndex {
+    fn to_string(&self, _location_table: &LocationTable) -> String {
+        format!("{self:?}")
+    }
+}
+
+impl FactCell for PoloniusRegionVid {
+    fn to_string(&self, _location_table: &LocationTable) -> String {
+        format!("{self:?}")
+    }
+}
+
+impl FactCell for RegionVid {
+    fn to_string(&self, _location_table: &LocationTable) -> String {
         format!("{self:?}")
     }
 }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index e6f8ffd428d..d258c68b959 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -7,7 +7,6 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(let_chains)]
-#![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
 #![feature(rustdoc_internals)]
@@ -728,6 +727,12 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
                 }
                 self.mutate_place(loc, (*destination, span), Deep, flow_state);
             }
+            TerminatorKind::TailCall { func, args, fn_span: _ } => {
+                self.consume_operand(loc, (func, span), flow_state);
+                for arg in args {
+                    self.consume_operand(loc, (&arg.node, arg.span), flow_state);
+                }
+            }
             TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
                 self.consume_operand(loc, (cond, span), flow_state);
                 if let AssertKind::BoundsCheck { len, index } = &**msg {
@@ -814,9 +819,8 @@ impl<'a, 'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
 
             TerminatorKind::UnwindResume
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::CoroutineDrop => {
-                // Returning from the function implicitly kills storage for all locals and statics.
-                // Often, the storage will already have been killed by an explicit
                 // StorageDead, but we don't always emit those (notably on unwind paths),
                 // so this "extra check" serves as a kind of backup.
                 let borrow_set = self.borrow_set.clone();
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index 6979910a02d..30dfc4c21b0 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -125,6 +125,12 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
                 }
                 self.mutate_place(location, *destination, Deep);
             }
+            TerminatorKind::TailCall { func, args, .. } => {
+                self.consume_operand(location, func);
+                for arg in args {
+                    self.consume_operand(location, &arg.node);
+                }
+            }
             TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
                 self.consume_operand(location, cond);
                 use rustc_middle::mir::AssertKind;
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index c56eaaff076..44a84fb9d7f 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -62,7 +62,7 @@ pub struct RegionTracker {
     /// The representative Region Variable Id for this SCC. We prefer
     /// placeholders over existentially quantified variables, otherwise
     ///  it's the one with the smallest Region Variable ID.
-    representative: RegionVid,
+    pub(crate) representative: RegionVid,
 
     /// Is the current representative a placeholder?
     representative_is_placeholder: bool,
@@ -97,7 +97,7 @@ impl scc::Annotation for RegionTracker {
 }
 
 impl RegionTracker {
-    fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
+    pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
         let (representative_is_placeholder, representative_is_existential) = match definition.origin
         {
             rustc_infer::infer::NllRegionVariableOrigin::FreeRegion => (false, false),
@@ -116,7 +116,9 @@ impl RegionTracker {
             representative_is_existential,
         }
     }
-    fn universe(self) -> UniverseIndex {
+
+    /// The smallest-indexed universe reachable from and/or in this SCC.
+    fn min_universe(self) -> UniverseIndex {
         self.min_reachable_universe
     }
 
@@ -132,8 +134,8 @@ impl RegionTracker {
 
     /// Returns `true` if during the annotated SCC reaches a placeholder
     /// with a universe larger than the smallest reachable one, `false` otherwise.
-    pub fn has_incompatible_universes(&self) -> bool {
-        self.universe().cannot_name(self.max_placeholder_universe_reached)
+    pub(crate) fn has_incompatible_universes(&self) -> bool {
+        self.min_universe().cannot_name(self.max_placeholder_universe_reached)
     }
 }
 
@@ -163,7 +165,7 @@ pub struct RegionInferenceContext<'tcx> {
     /// The SCC computed from `constraints` and the constraint
     /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
     /// compute the values of each region.
-    constraint_sccs: Rc<ConstraintSccs>,
+    constraint_sccs: ConstraintSccs,
 
     /// Reverse of the SCC constraint graph --  i.e., an edge `A -> B` exists if
     /// `B: A`. This is used to compute the universal regions that are required
@@ -401,7 +403,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         universal_regions: Rc<UniversalRegions<'tcx>>,
         placeholder_indices: Rc<PlaceholderIndices>,
         universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-        outlives_constraints: OutlivesConstraintSet<'tcx>,
+        mut outlives_constraints: OutlivesConstraintSet<'tcx>,
         member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
         universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
         type_tests: Vec<TypeTest<'tcx>>,
@@ -419,17 +421,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             .map(|info| RegionDefinition::new(info.universe, info.origin))
             .collect();
 
-        let fr_static = universal_regions.fr_static;
+        let constraint_sccs =
+            outlives_constraints.add_outlives_static(&universal_regions, &definitions);
         let constraints = Frozen::freeze(outlives_constraints);
         let constraint_graph = Frozen::freeze(constraints.graph(definitions.len()));
-        let constraint_sccs = {
-            let constraint_graph = constraints.graph(definitions.len());
-            let region_graph = &constraint_graph.region_graph(&constraints, fr_static);
-            let sccs = ConstraintSccs::new_with_annotation(&region_graph, |r| {
-                RegionTracker::new(r, &definitions[r])
-            });
-            Rc::new(sccs)
-        };
 
         if cfg!(debug_assertions) {
             sccs_info(infcx, &constraint_sccs);
@@ -548,21 +543,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 }
 
                 NllRegionVariableOrigin::Placeholder(placeholder) => {
-                    // Each placeholder region is only visible from
-                    // its universe `ui` and its extensions. So we
-                    // can't just add it into `scc` unless the
-                    // universe of the scc can name this region.
-                    let scc_universe = self.scc_universe(scc);
-                    if scc_universe.can_name(placeholder.universe) {
-                        self.scc_values.add_element(scc, placeholder);
-                    } else {
-                        debug!(
-                            "init_free_and_bound_regions: placeholder {:?} is \
-                             not compatible with universe {:?} of its SCC {:?}",
-                            placeholder, scc_universe, scc,
-                        );
-                        self.add_incompatible_universe(scc);
-                    }
+                    self.scc_values.add_element(scc, placeholder);
                 }
 
                 NllRegionVariableOrigin::Existential { .. } => {
@@ -744,23 +725,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// (which is assured by iterating over SCCs in dependency order).
     #[instrument(skip(self), level = "debug")]
     fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) {
-        let constraint_sccs = self.constraint_sccs.clone();
-
         // Walk each SCC `B` such that `A: B`...
-        for &scc_b in constraint_sccs.successors(scc_a) {
+        for &scc_b in self.constraint_sccs.successors(scc_a) {
             debug!(?scc_b);
-
-            // ...and add elements from `B` into `A`. One complication
-            // arises because of universes: If `B` contains something
-            // that `A` cannot name, then `A` can only contain `B` if
-            // it outlives static.
-            if self.universe_compatible(scc_b, scc_a) {
-                // `A` can name everything that is in `B`, so just
-                // merge the bits.
-                self.scc_values.add_region(scc_a, scc_b);
-            } else {
-                self.add_incompatible_universe(scc_a);
-            }
+            self.scc_values.add_region(scc_a, scc_b);
         }
 
         // Now take member constraints into account.
@@ -814,7 +782,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // If the member region lives in a higher universe, we currently choose
         // the most conservative option by leaving it unchanged.
 
-        if !self.constraint_sccs().annotation(scc).universe().is_root() {
+        if !self.constraint_sccs().annotation(scc).min_universe().is_root() {
             return;
         }
 
@@ -886,35 +854,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// in `scc_a`. Used during constraint propagation, and only once
     /// the value of `scc_b` has been computed.
     fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool {
-        let universe_a = self.constraint_sccs().annotation(scc_a).universe();
-        let universe_b = self.constraint_sccs().annotation(scc_b).universe();
+        let a_annotation = self.constraint_sccs().annotation(scc_a);
+        let b_annotation = self.constraint_sccs().annotation(scc_b);
+        let a_universe = a_annotation.min_universe();
 
-        // Quick check: if scc_b's declared universe is a subset of
+        // If scc_b's declared universe is a subset of
         // scc_a's declared universe (typically, both are ROOT), then
         // it cannot contain any problematic universe elements.
-        if universe_a.can_name(universe_b) {
+        if a_universe.can_name(b_annotation.min_universe()) {
             return true;
         }
 
-        // Otherwise, we have to iterate over the universe elements in
-        // B's value, and check whether all of them are nameable
-        // from universe_a
-        self.scc_values.placeholders_contained_in(scc_b).all(|p| universe_a.can_name(p.universe))
-    }
-
-    /// Extend `scc` so that it can outlive some placeholder region
-    /// from a universe it can't name; at present, the only way for
-    /// this to be true is if `scc` outlives `'static`. This is
-    /// actually stricter than necessary: ideally, we'd support bounds
-    /// like `for<'a: 'b>` that might then allow us to approximate
-    /// `'a` with `'b` and not `'static`. But it will have to do for
-    /// now.
-    fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
-        debug!("add_incompatible_universe(scc={:?})", scc);
-
-        let fr_static = self.universal_regions.fr_static;
-        self.scc_values.add_all_points(scc);
-        self.scc_values.add_element(scc, fr_static);
+        // Otherwise, there can be no placeholder in `b` with a too high
+        // universe index to name from `a`.
+        a_universe.can_name(b_annotation.max_placeholder_universe_reached)
     }
 
     /// Once regions have been propagated, this method is used to see
@@ -1022,7 +975,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             "lower_bound = {:?} r_scc={:?} universe={:?}",
             lower_bound,
             r_scc,
-            self.constraint_sccs.annotation(r_scc).universe()
+            self.constraint_sccs.annotation(r_scc).min_universe()
         );
 
         // If the type test requires that `T: 'a` where `'a` is a
@@ -1539,7 +1492,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// The minimum universe of any variable reachable from this
     /// SCC, inside or outside of it.
     fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
-        self.constraint_sccs().annotation(scc).universe()
+        self.constraint_sccs().annotation(scc).min_universe()
     }
     /// Checks the final value for the free region `fr` to see if it
     /// grew too large. In particular, examine what `end(X)` points
@@ -1896,6 +1849,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             // This loop can be hot.
             for constraint in outgoing_edges_from_graph {
+                if matches!(constraint.category, ConstraintCategory::IllegalUniverse) {
+                    debug!("Ignoring illegal universe constraint: {constraint:?}");
+                    continue;
+                }
                 handle_constraint(constraint);
             }
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index e195ceded1b..c0e91ce32e3 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 7553e3ee04f..431a704687d 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -11,8 +11,8 @@ use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
 use rustc_span::{ErrorGuaranteed, Span};
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::solve::deeply_normalize;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
 use type_op::TypeOpOutput;
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index aa25e3adf28..db4b5209145 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -38,6 +38,7 @@ use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use rustc_span::DUMMY_SP;
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -49,6 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
 
+use crate::renumber::RegionCtxt;
 use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
 use crate::{
     borrow_set::BorrowSet,
@@ -1352,7 +1354,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
                 // FIXME: check the values
             }
-            TerminatorKind::Call { func, args, destination, call_source, target, .. } => {
+            TerminatorKind::Call { func, args, .. }
+            | TerminatorKind::TailCall { func, args, .. } => {
+                let call_source = match term.kind {
+                    TerminatorKind::Call { call_source, .. } => call_source,
+                    TerminatorKind::TailCall { .. } => CallSource::Normal,
+                    _ => unreachable!(),
+                };
+
                 self.check_operand(func, term_location);
                 for arg in args {
                     self.check_operand(&arg.node, term_location);
@@ -1425,7 +1434,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     );
                 }
 
-                self.check_call_dest(body, term, &sig, *destination, *target, term_location);
+                if let TerminatorKind::Call { destination, target, .. } = term.kind {
+                    self.check_call_dest(body, term, &sig, destination, target, term_location);
+                }
 
                 // The ordinary liveness rules will ensure that all
                 // regions in the type of the callee are live here. We
@@ -1443,7 +1454,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         .add_location(region_vid, term_location);
                 }
 
-                self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source);
+                self.check_call_inputs(body, term, func, &sig, args, term_location, call_source);
             }
             TerminatorKind::Assert { cond, msg, .. } => {
                 self.check_operand(cond, term_location);
@@ -1675,6 +1686,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     span_mirbug!(self, block_data, "return on cleanup block")
                 }
             }
+            TerminatorKind::TailCall { .. } => {
+                if is_cleanup {
+                    span_mirbug!(self, block_data, "tailcall on cleanup block")
+                }
+            }
             TerminatorKind::CoroutineDrop { .. } => {
                 if is_cleanup {
                     span_mirbug!(self, block_data, "coroutine_drop in cleanup block")
@@ -2319,7 +2335,57 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
-                            (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => (),
+                            (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
+                                let mut normalize = |t| self.normalize(t, location);
+                                let src_tail =
+                                    tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
+                                let dst_tail =
+                                    tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
+
+                                // This checks (lifetime part of) vtable validity for pointer casts,
+                                // which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).
+                                //
+                                // Note that other checks (such as denying `dyn Send` -> `dyn Debug`) are in `rustc_hir_typeck`.
+                                if let ty::Dynamic(src_tty, ..) = src_tail.kind()
+                                    && let ty::Dynamic(dst_tty, ..) = dst_tail.kind()
+                                    && src_tty.principal().is_some()
+                                    && dst_tty.principal().is_some()
+                                {
+                                    // Remove auto traits.
+                                    // Auto trait checks are handled in `rustc_hir_typeck` as FCW.
+                                    let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(
+                                        tcx.mk_poly_existential_predicates(
+                                            &src_tty.without_auto_traits().collect::<Vec<_>>(),
+                                        ),
+                                        tcx.lifetimes.re_static,
+                                        ty::Dyn,
+                                    ));
+                                    let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(
+                                        tcx.mk_poly_existential_predicates(
+                                            &dst_tty.without_auto_traits().collect::<Vec<_>>(),
+                                        ),
+                                        tcx.lifetimes.re_static,
+                                        ty::Dyn,
+                                    ));
+
+                                    // Replace trait object lifetimes with fresh vars, to allow casts like
+                                    // `*mut dyn FnOnce() + 'a` -> `*mut dyn FnOnce() + 'static`,
+                                    let src_obj =
+                                        freshen_single_trait_object_lifetime(self.infcx, src_obj);
+                                    let dst_obj =
+                                        freshen_single_trait_object_lifetime(self.infcx, dst_obj);
+
+                                    debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
+
+                                    self.eq_types(
+                                        src_obj,
+                                        dst_obj,
+                                        location.to_locations(),
+                                        ConstraintCategory::Cast { unsize_to: None },
+                                    )
+                                    .unwrap();
+                                }
+                            }
                             _ => {
                                 span_mirbug!(
                                     self,
@@ -2842,3 +2908,16 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
         Ok(output)
     }
 }
+
+fn freshen_single_trait_object_lifetime<'tcx>(
+    infcx: &BorrowckInferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Ty<'tcx> {
+    let &ty::Dynamic(tty, _, dyn_kind @ ty::Dyn) = ty.kind() else { bug!("expected trait object") };
+
+    let fresh = infcx
+        .next_region_var(rustc_infer::infer::RegionVariableOrigin::MiscVariable(DUMMY_SP), || {
+            RegionCtxt::Unknown
+        });
+    infcx.tcx.mk_ty_from_kind(ty::Dynamic(tty, fresh, dyn_kind))
+}
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index b9a82046e59..02b9c2d48b1 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,8 +1,9 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
-use rustc_infer::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
-use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation};
-use rustc_infer::infer::NllRegionVariableOrigin;
+use rustc_infer::infer::relate::{
+    PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
+};
+use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_infer::traits::solve::Goal;
 use rustc_infer::traits::Obligation;
 use rustc_middle::mir::ConstraintCategory;
@@ -522,7 +523,7 @@ impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx
     }
 }
 
-impl<'bccx, 'tcx> PredicateEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
+impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> {
     fn span(&self) -> Span {
         self.locations.span(self.type_checker.body)
     }
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 2d1269e1b6a..b56bfa98357 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -17,6 +17,9 @@ builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
     *[false] clobber_abi, options
     }, or additional template string
 
+builtin_macros_asm_expected_string_literal = expected string literal
+    .label = not a string literal
+
 builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
 
 builtin_macros_asm_mayunwind = asm labels are not allowed with the `may_unwind` option
@@ -25,6 +28,8 @@ builtin_macros_asm_modifier_invalid = asm template modifier must be a single cha
 
 builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
 
+builtin_macros_asm_no_matched_argument_name = there is no argument named `{$name}`
+
 builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option
 
 builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided
@@ -228,10 +233,16 @@ builtin_macros_only_one_argument = {$name} takes 1 argument
 
 builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
 
+builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions = the `#[{$path}]` attribute may only be used on bare functions
+
+builtin_macros_proc_macro_attribute_only_usable_with_crate_type = the `#[{$path}]` attribute is only usable with crates of the `proc-macro` crate type
+
 builtin_macros_requires_cfg_pattern =
     macro requires a cfg-pattern as an argument
     .label = cfg-pattern required
 
+builtin_macros_source_uitls_expected_item = expected item, found `{$token}`
+
 builtin_macros_takes_no_arguments = {$name} takes no arguments
 
 builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 64238e81b26..dd0f9aaf221 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -390,9 +390,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
             }
             Err(opt_lit) => {
                 let span = opt_lit.map_or(p.token.span, |lit| lit.span);
-                let mut err = p.dcx().struct_span_err(span, "expected string literal");
-                err.span_label(span, "not a string literal");
-                return Err(err);
+                return Err(p.dcx().create_err(errors::AsmExpectedStringLiteral { span }));
             }
         };
 
@@ -639,14 +637,13 @@ fn expand_preparsed_asm(
                             match args.named_args.get(&Symbol::intern(name)) {
                                 Some(&idx) => Some(idx),
                                 None => {
-                                    let msg = format!("there is no argument named `{name}`");
                                     let span = arg.position_span;
                                     ecx.dcx()
-                                        .struct_span_err(
-                                            template_span
+                                        .create_err(errors::AsmNoMatchedArgumentName {
+                                            name: name.to_owned(),
+                                            span: template_span
                                                 .from_inner(InnerSpan::new(span.start, span.end)),
-                                            msg,
-                                        )
+                                        })
                                         .emit();
                                     None
                                 }
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 03aff6f9633..b09975c0ba7 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -38,16 +38,14 @@ pub(crate) fn cfg_eval(
     lint_node_id: NodeId,
 ) -> Annotatable {
     let features = Some(features);
-    CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true, lint_node_id } }
+    CfgEval(StripUnconfigured { sess, features, config_tokens: true, lint_node_id })
         .configure_annotatable(annotatable)
         // Since the item itself has already been configured by the `InvocationCollector`,
         // we know that fold result vector will contain exactly one element.
         .unwrap()
 }
 
-struct CfgEval<'a, 'b> {
-    cfg: &'a mut StripUnconfigured<'b>,
-}
+struct CfgEval<'a>(StripUnconfigured<'a>);
 
 fn flat_map_annotatable(
     vis: &mut impl MutVisitor,
@@ -125,9 +123,9 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
     res.is_break()
 }
 
-impl CfgEval<'_, '_> {
+impl CfgEval<'_> {
     fn configure<T: HasAttrs + HasTokens>(&mut self, node: T) -> Option<T> {
-        self.cfg.configure(node)
+        self.0.configure(node)
     }
 
     fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> {
@@ -195,8 +193,8 @@ impl CfgEval<'_, '_> {
 
         // Re-parse the tokens, setting the `capture_cfg` flag to save extra information
         // to the captured `AttrTokenStream` (specifically, we capture
-        // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
-        let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None);
+        // `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
+        let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None);
         parser.capture_cfg = true;
         match parse_annotatable_with(&mut parser) {
             Ok(a) => annotatable = a,
@@ -212,16 +210,16 @@ impl CfgEval<'_, '_> {
     }
 }
 
-impl MutVisitor for CfgEval<'_, '_> {
+impl MutVisitor for CfgEval<'_> {
     #[instrument(level = "trace", skip(self))]
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
-        self.cfg.configure_expr(expr, false);
+        self.0.configure_expr(expr, false);
         mut_visit::noop_visit_expr(expr, self);
     }
 
     #[instrument(level = "trace", skip(self))]
     fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
-        self.cfg.configure_expr(expr, true);
+        self.0.configure_expr(expr, true);
         mut_visit::noop_visit_expr(expr, self);
     }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 577523a1d5a..7a65ed97f00 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -240,7 +240,7 @@ fn has_a_default_variant(item: &Annotatable) -> bool {
             if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
                 ControlFlow::Break(())
             } else {
-                // no need to subrecurse.
+                // no need to walk the variant, we are only looking for top level variants
                 ControlFlow::Continue(())
             }
         }
diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
index ea054a7e355..bbc7cd39627 100644
--- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
@@ -3,8 +3,9 @@ use std::mem::swap;
 use ast::HasAttrs;
 use rustc_ast::{
     self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem,
-    TraitBoundModifiers,
+    TraitBoundModifiers, VariantData,
 };
+use rustc_attr as attr;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -24,11 +25,43 @@ pub fn expand_deriving_smart_ptr(
     _is_const: bool,
 ) {
     let (name_ident, generics) = if let Annotatable::Item(aitem) = item
-        && let ItemKind::Struct(_, g) = &aitem.kind
+        && let ItemKind::Struct(struct_data, g) = &aitem.kind
     {
+        let is_transparent = aitem.attrs.iter().any(|attr| {
+            attr::find_repr_attrs(cx.sess, attr)
+                .into_iter()
+                .any(|r| matches!(r, attr::ReprTransparent))
+        });
+        if !is_transparent {
+            cx.dcx()
+                .struct_span_err(
+                    span,
+                    "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
+                )
+                .emit();
+            return;
+        }
+        if !matches!(
+            struct_data,
+            VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _)
+                if !fields.is_empty())
+        {
+            cx.dcx()
+                .struct_span_err(
+                    span,
+                    "`SmartPointer` can only be derived on `struct`s with at least one field",
+                )
+                .emit();
+            return;
+        }
         (aitem.ident, g)
     } else {
-        cx.dcx().struct_span_err(span, "`SmartPointer` can only be derived on `struct`s").emit();
+        cx.dcx()
+            .struct_span_err(
+                span,
+                "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
+            )
+            .emit();
         return;
     };
 
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index ed2f98f2a39..49d640436c2 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -729,6 +729,14 @@ pub(crate) struct AsmExpectedComma {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_asm_expected_string_literal)]
+pub(crate) struct AsmExpectedStringLiteral {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_asm_underscore_input)]
 pub(crate) struct AsmUnderscoreInput {
     #[primary_span]
@@ -782,6 +790,14 @@ pub(crate) struct AsmNoReturn {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_asm_no_matched_argument_name)]
+pub(crate) struct AsmNoMatchedArgumentName {
+    pub(crate) name: String,
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_asm_mayunwind)]
 pub(crate) struct AsmMayUnwind {
     #[primary_span]
@@ -872,3 +888,27 @@ pub(crate) struct TakesNoArguments<'a> {
     pub span: Span,
     pub name: &'a str,
 }
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions)]
+pub(crate) struct AttributeOnlyBeUsedOnBareFunctions<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub path: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_proc_macro_attribute_only_usable_with_crate_type)]
+pub(crate) struct AttributeOnlyUsableWithCrateType<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub path: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_source_uitls_expected_item)]
+pub(crate) struct ExpectedItem<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub token: &'a str,
+}
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 99d0191958d..a8a595ea579 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -214,12 +214,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         };
 
         if !is_fn {
-            let msg = format!(
-                "the `#[{}]` attribute may only be used on bare functions",
-                pprust::path_to_string(&attr.get_normal_item().path),
-            );
-
-            self.dcx.span_err(attr.span, msg);
+            self.dcx
+                .create_err(errors::AttributeOnlyBeUsedOnBareFunctions {
+                    span: attr.span,
+                    path: &pprust::path_to_string(&attr.get_normal_item().path),
+                })
+                .emit();
             return;
         }
 
@@ -228,12 +228,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         }
 
         if !self.is_proc_macro_crate {
-            let msg = format!(
-                "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type",
-                pprust::path_to_string(&attr.get_normal_item().path),
-            );
-
-            self.dcx.span_err(attr.span, msg);
+            self.dcx
+                .create_err(errors::AttributeOnlyUsableWithCrateType {
+                    span: attr.span,
+                    path: &pprust::path_to_string(&attr.get_normal_item().path),
+                })
+                .emit();
             return;
         }
 
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index dc1d82df0c3..44db12cf695 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -1,3 +1,4 @@
+use crate::errors;
 use crate::util::{
     check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
 };
@@ -165,9 +166,13 @@ pub(crate) fn expand_include<'cx>(
                     Ok(Some(item)) => ret.push(item),
                     Ok(None) => {
                         if self.p.token != token::Eof {
-                            let token = pprust::token_to_string(&self.p.token);
-                            let msg = format!("expected item, found `{token}`");
-                            self.p.dcx().span_err(self.p.token.span, msg);
+                            self.p
+                                .dcx()
+                                .create_err(errors::ExpectedItem {
+                                    span: self.p.token.span,
+                                    token: &pprust::token_to_string(&self.p.token),
+                                })
+                                .emit();
                         }
 
                         break;
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 0d7eee7afb4..9dc94ab33ea 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -371,9 +371,14 @@ pub(crate) fn codegen_terminator_call<'tcx>(
 
     // Handle special calls like intrinsics and empty drop glue.
     let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() {
-        let instance =
-            ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args)
-                .polymorphize(fx.tcx);
+        let instance = ty::Instance::expect_resolve(
+            fx.tcx,
+            ty::ParamEnv::reveal_all(),
+            def_id,
+            fn_args,
+            source_info.span,
+        )
+        .polymorphize(fx.tcx);
 
         if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
             if target.is_some() {
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index c5b4277015a..5adbbb09ac8 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -491,6 +491,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                     )
                 });
             }
+            // FIXME(explicit_tail_calls): add support for tail calls to the cranelift backend, once cranelift supports tail calls
+            TerminatorKind::TailCall { fn_span, .. } => span_bug!(
+                *fn_span,
+                "tail calls are not yet supported in `rustc_codegen_cranelift` backend"
+            ),
             TerminatorKind::InlineAsm {
                 template,
                 operands,
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 87c5da3b7c3..fd34ed88c0b 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -155,7 +155,7 @@ pub(crate) fn codegen_const_value<'tcx>(
                             fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
                         }
                     }
-                    GlobalAlloc::Function(instance) => {
+                    GlobalAlloc::Function { instance, .. } => {
                         let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);
                         let local_func_id =
                             fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
@@ -351,7 +351,9 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
             TodoItem::Alloc(alloc_id) => {
                 let alloc = match tcx.global_alloc(alloc_id) {
                     GlobalAlloc::Memory(alloc) => alloc,
-                    GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => {
+                    GlobalAlloc::Function { .. }
+                    | GlobalAlloc::Static(_)
+                    | GlobalAlloc::VTable(..) => {
                         unreachable!()
                     }
                 };
@@ -415,7 +417,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
 
             let reloc_target_alloc = tcx.global_alloc(alloc_id);
             let data_id = match reloc_target_alloc {
-                GlobalAlloc::Function(instance) => {
+                GlobalAlloc::Function { instance, .. } => {
                     assert_eq!(addend, 0);
                     let func_id =
                         crate::abi::import_function(tcx, module, instance.polymorphize(tcx));
@@ -565,6 +567,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                     {
                         return None;
                     }
+                    TerminatorKind::TailCall { .. } => return None,
                     TerminatorKind::Call { .. } => {}
                 }
             }
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 33d3f9b8a90..fe0a1551419 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -4,6 +4,7 @@ use rustc_middle::ty::AssocKind;
 use rustc_middle::ty::GenericArg;
 use rustc_session::config::{sigpipe, EntryFnType};
 use rustc_span::symbol::Ident;
+use rustc_span::DUMMY_SP;
 
 use crate::prelude::*;
 
@@ -119,6 +120,7 @@ pub(crate) fn maybe_create_entry_wrapper(
                     ParamEnv::reveal_all(),
                     report.def_id,
                     tcx.mk_args(&[GenericArg::from(main_ret_ty)]),
+                    DUMMY_SP,
                 )
                 .polymorphize(tcx);
 
@@ -144,6 +146,7 @@ pub(crate) fn maybe_create_entry_wrapper(
                     ParamEnv::reveal_all(),
                     start_def_id,
                     tcx.mk_args(&[main_ret_ty.into()]),
+                    DUMMY_SP,
                 )
                 .polymorphize(tcx);
                 let start_func_id = import_function(tcx, m, start_instance);
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index 230fe4f5871..fa8a1ec037c 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -220,7 +220,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                         }
                         value
                     }
-                    GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance),
+                    GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance),
                     GlobalAlloc::VTable(ty, trait_ref) => {
                         let alloc = self
                             .tcx
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 6231b09552c..1d689c9ac0e 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::layout::{
 };
 use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
 use rustc_session::Session;
-use rustc_span::{source_map::respan, Span};
+use rustc_span::{source_map::respan, Span, DUMMY_SP};
 use rustc_target::abi::{
     call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
 };
@@ -479,6 +479,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                     ty::ParamEnv::reveal_all(),
                     def_id,
                     ty::List::empty(),
+                    DUMMY_SP,
                 );
 
                 let symbol_name = tcx.symbol_name(instance).name;
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index a6a3f0f9646..d034f9b5256 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -226,7 +226,8 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 //   when passed by value, making it smaller.
                 // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
                 //   when passed by value, making it larger.
-                let copy_bytes = cmp::min(scratch_size.bytes(), self.layout.size.bytes());
+                let copy_bytes =
+                    cmp::min(cast.unaligned_size(bx).bytes(), self.layout.size.bytes());
                 // Allocate some scratch space...
                 let llscratch = bx.alloca(scratch_size, scratch_align);
                 bx.lifetime_start(llscratch, scratch_size);
diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
index 28a88dd2efe..b72636a6224 100644
--- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
+++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
@@ -32,7 +32,7 @@ impl OwnedTargetMachine {
         unique_section_names: bool,
         trap_unreachable: bool,
         singletree: bool,
-        asm_comments: bool,
+        verbose_asm: bool,
         emit_stack_size_section: bool,
         relax_elf_relocations: bool,
         use_init_array: bool,
@@ -64,7 +64,7 @@ impl OwnedTargetMachine {
                 unique_section_names,
                 trap_unreachable,
                 singletree,
-                asm_comments,
+                verbose_asm,
                 emit_stack_size_section,
                 relax_elf_relocations,
                 use_init_array,
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 5e481eb98f5..2fda19bf0c9 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -214,7 +214,7 @@ pub fn target_machine_factory(
         sess.opts.unstable_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable);
     let emit_stack_size_section = sess.opts.unstable_opts.emit_stack_sizes;
 
-    let asm_comments = sess.opts.unstable_opts.asm_comments;
+    let verbose_asm = sess.opts.unstable_opts.verbose_asm;
     let relax_elf_relocations =
         sess.opts.unstable_opts.relax_elf_relocations.unwrap_or(sess.target.relax_elf_relocations);
 
@@ -289,7 +289,7 @@ pub fn target_machine_factory(
             funique_section_names,
             trap_unreachable,
             singlethread,
-            asm_comments,
+            verbose_asm,
             emit_stack_size_section,
             relax_elf_relocations,
             use_init_array,
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index d42c6ed827a..fe64649cf70 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -289,8 +289,8 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                             (value, AddressSpace::DATA)
                         }
                     }
-                    GlobalAlloc::Function(fn_instance) => (
-                        self.get_fn_addr(fn_instance.polymorphize(self.tcx)),
+                    GlobalAlloc::Function { instance, .. } => (
+                        self.get_fn_addr(instance.polymorphize(self.tcx)),
                         self.data_layout().instruction_address_space,
                     ),
                     GlobalAlloc::VTable(ty, trait_ref) => {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 1a8e8efdae5..77beb9a6bb3 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -28,7 +28,7 @@ use rustc_session::config::{BranchProtection, CFGuard, CFProtection};
 use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{call::FnAbi, HasDataLayout, TargetDataLayout, VariantIdx};
 use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
 use smallvec::SmallVec;
@@ -580,6 +580,7 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 ty::ParamEnv::reveal_all(),
                 def_id,
                 ty::List::empty(),
+                DUMMY_SP,
             )),
             _ => {
                 let name = name.unwrap_or("rust_eh_personality");
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 742bfd76590..851a4c42e99 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -705,10 +705,12 @@ impl MsvcBasicName for ty::UintTy {
 
 impl MsvcBasicName for ty::FloatTy {
     fn msvc_basic_name(self) -> &'static str {
-        // FIXME: f16 and f128 have no MSVC representation. We could improve the debuginfo.
-        // See: <https://github.com/rust-lang/rust/pull/114607/files#r1454683264>
+        // FIXME(f16_f128): `f16` and `f128` have no MSVC representation. We could improve the
+        // debuginfo. See: <https://github.com/rust-lang/rust/issues/121837>
         match self {
-            ty::FloatTy::F16 => "half",
+            ty::FloatTy::F16 => {
+                bug!("`f16` should have been handled in `build_basic_type_di_node`")
+            }
             ty::FloatTy::F32 => "float",
             ty::FloatTy::F64 => "double",
             ty::FloatTy::F128 => "fp128",
@@ -716,6 +718,38 @@ impl MsvcBasicName for ty::FloatTy {
     }
 }
 
+fn build_cpp_f16_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> DINodeCreationResult<'ll> {
+    // MSVC has no native support for `f16`. Instead, emit `struct f16 { bits: u16 }` to allow the
+    // `f16`'s value to be displayed using a Natvis visualiser in `intrinsic.natvis`.
+    let float_ty = cx.tcx.types.f16;
+    let bits_ty = cx.tcx.types.u16;
+    type_map::build_type_with_children(
+        cx,
+        type_map::stub(
+            cx,
+            Stub::Struct,
+            UniqueTypeId::for_ty(cx.tcx, float_ty),
+            "f16",
+            cx.size_and_align_of(float_ty),
+            NO_SCOPE_METADATA,
+            DIFlags::FlagZero,
+        ),
+        // Fields:
+        |cx, float_di_node| {
+            smallvec![build_field_di_node(
+                cx,
+                float_di_node,
+                "bits",
+                cx.size_and_align_of(bits_ty),
+                Size::ZERO,
+                DIFlags::FlagZero,
+                type_di_node(cx, bits_ty),
+            )]
+        },
+        NO_GENERICS,
+    )
+}
+
 fn build_basic_type_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     t: Ty<'tcx>,
@@ -739,6 +773,9 @@ fn build_basic_type_di_node<'ll, 'tcx>(
         ty::Char => ("char", DW_ATE_UTF),
         ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
         ty::Uint(uint_ty) if cpp_like_debuginfo => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
+        ty::Float(ty::FloatTy::F16) if cpp_like_debuginfo => {
+            return build_cpp_f16_di_node(cx);
+        }
         ty::Float(float_ty) if cpp_like_debuginfo => (float_ty.msvc_basic_name(), DW_ATE_float),
         ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed),
         ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned),
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index b5b0086f740..e02c61cd296 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1121,8 +1121,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     if name == sym::simd_select_bitmask {
         let (len, _) = require_simd!(arg_tys[1], SimdArgument);
 
-        let expected_int_bits = (len.max(8) - 1).next_power_of_two();
-        let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
+        let expected_int_bits = len.max(8).next_power_of_two();
+        let expected_bytes = len.div_ceil(8);
 
         let mask_ty = arg_tys[0];
         let mask = match mask_ty.kind() {
@@ -1379,17 +1379,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     }
 
     if name == sym::simd_bitmask {
-        // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
-        // vector mask and returns the most significant bit (MSB) of each lane in the form
-        // of either:
+        // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a vector mask and
+        // returns one bit for each lane (which must all be `0` or `!0`) in the form of either:
         // * an unsigned integer
         // * an array of `u8`
         // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
         //
         // The bit order of the result depends on the byte endianness, LSB-first for little
         // endian and MSB-first for big endian.
-        let expected_int_bits = in_len.max(8);
-        let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64);
+        let expected_int_bits = in_len.max(8).next_power_of_two();
+        let expected_bytes = in_len.div_ceil(8);
 
         // Integer vector <i{in_bitwidth} x in_len>:
         let (i_xn, in_elem_bitwidth) = match in_elem.kind() {
@@ -1409,7 +1408,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             }),
         };
 
-        // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
+        // LLVM doesn't always know the inputs are `0` or `!0`, so we shift here so it optimizes to
+        // `pmovmskb` and similar on x86.
         let shift_indices =
             vec![
                 bx.cx.const_int(bx.type_ix(in_elem_bitwidth), (in_elem_bitwidth - 1) as _);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 132e1f9e8fd..08e9e312827 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2185,7 +2185,7 @@ extern "C" {
         UniqueSectionNames: bool,
         TrapUnreachable: bool,
         Singlethread: bool,
-        AsmComments: bool,
+        VerboseAsm: bool,
         EmitStackSizeSection: bool,
         RelaxELFRelocations: bool,
         UseInitArray: bool,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index d509e4ce56d..1f627353d54 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -45,7 +45,7 @@ use tempfile::Builder as TempFileBuilder;
 
 use itertools::Itertools;
 use std::collections::BTreeSet;
-use std::ffi::{OsStr, OsString};
+use std::ffi::OsString;
 use std::fs::{read, File, OpenOptions};
 use std::io::{BufWriter, Write};
 use std::ops::Deref;
@@ -1306,12 +1306,12 @@ fn link_sanitizer_runtime(
         let filename = format!("rustc{channel}_rt.{name}");
         let path = find_sanitizer_runtime(sess, &filename);
         let rpath = path.to_str().expect("non-utf8 component in path");
-        linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
+        linker.cc_args(&["-Wl,-rpath", "-Xlinker", rpath]);
         linker.link_dylib_by_name(&filename, false, true);
     } else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
         // MSVC provides the `/INFERASANLIBS` argument to automatically find the
         // compatible ASAN library.
-        linker.arg("/INFERASANLIBS");
+        linker.link_arg("/INFERASANLIBS");
     } else {
         let filename = format!("librustc{channel}_rt.{name}.a");
         let path = find_sanitizer_runtime(sess, &filename).join(&filename);
@@ -1888,9 +1888,9 @@ fn add_post_link_objects(
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
     if let Some(args) = sess.target.pre_link_args.get(&flavor) {
-        cmd.args(args.iter().map(Deref::deref));
+        cmd.verbatim_args(args.iter().map(Deref::deref));
     }
-    cmd.args(&sess.opts.unstable_opts.pre_link_args);
+    cmd.verbatim_args(&sess.opts.unstable_opts.pre_link_args);
 }
 
 /// Add a link script embedded in the target, if applicable.
@@ -1908,8 +1908,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty
                 sess.dcx().emit_fatal(errors::LinkScriptWriteFailure { path, error });
             }
 
-            cmd.arg("--script");
-            cmd.arg(path);
+            cmd.link_arg("--script").link_arg(path);
         }
         _ => {}
     }
@@ -1918,7 +1917,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty
 /// Add arbitrary "user defined" args defined from command line.
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_user_defined_link_args(cmd: &mut dyn Linker, sess: &Session) {
-    cmd.args(&sess.opts.cg.link_args);
+    cmd.verbatim_args(&sess.opts.cg.link_args);
 }
 
 /// Add arbitrary "late link" args defined by the target spec.
@@ -1936,15 +1935,15 @@ fn add_late_link_args(
         });
     if any_dynamic_crate {
         if let Some(args) = sess.target.late_link_args_dynamic.get(&flavor) {
-            cmd.args(args.iter().map(Deref::deref));
+            cmd.verbatim_args(args.iter().map(Deref::deref));
         }
     } else {
         if let Some(args) = sess.target.late_link_args_static.get(&flavor) {
-            cmd.args(args.iter().map(Deref::deref));
+            cmd.verbatim_args(args.iter().map(Deref::deref));
         }
     }
     if let Some(args) = sess.target.late_link_args.get(&flavor) {
-        cmd.args(args.iter().map(Deref::deref));
+        cmd.verbatim_args(args.iter().map(Deref::deref));
     }
 }
 
@@ -1952,7 +1951,7 @@ fn add_late_link_args(
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
     if let Some(args) = sess.target.post_link_args.get(&flavor) {
-        cmd.args(args.iter().map(Deref::deref));
+        cmd.verbatim_args(args.iter().map(Deref::deref));
     }
 }
 
@@ -2097,6 +2096,10 @@ fn add_rpath_args(
     codegen_results: &CodegenResults,
     out_filename: &Path,
 ) {
+    if !sess.target.has_rpath {
+        return;
+    }
+
     // FIXME (#2397): At some point we want to rpath our guesses as to
     // where extern libraries might live, based on the
     // add_lib_search_paths
@@ -2115,11 +2118,10 @@ fn add_rpath_args(
         let rpath_config = RPathConfig {
             libs: &*libs,
             out_filename: out_filename.to_path_buf(),
-            has_rpath: sess.target.has_rpath,
             is_like_osx: sess.target.is_like_osx,
             linker_is_gnu: sess.target.linker_flavor.is_gnu(),
         };
-        cmd.args(&rpath::get_rpath_flags(&rpath_config));
+        cmd.cc_args(&rpath::get_rpath_flags(&rpath_config));
     }
 }
 
@@ -2378,7 +2380,7 @@ fn add_order_independent_options(
         } else {
             ""
         };
-        cmd.arg(format!("--dynamic-linker={prefix}ld.so.1"));
+        cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1"));
     }
 
     if sess.target.eh_frame_header {
@@ -2393,8 +2395,7 @@ fn add_order_independent_options(
     }
 
     if sess.target.os == "emscripten" {
-        cmd.arg("-s");
-        cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
+        cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
             "DISABLE_EXCEPTION_CATCHING=1"
         } else {
             "DISABLE_EXCEPTION_CATCHING=0"
@@ -2402,22 +2403,21 @@ fn add_order_independent_options(
     }
 
     if flavor == LinkerFlavor::Llbc {
-        cmd.arg("--target");
-        cmd.arg(sess.target.llvm_target.as_ref());
-        cmd.arg("--target-cpu");
-        cmd.arg(&codegen_results.crate_info.target_cpu);
+        cmd.link_args(&[
+            "--target",
+            sess.target.llvm_target.as_ref(),
+            "--target-cpu",
+            &codegen_results.crate_info.target_cpu,
+        ]);
     } else if flavor == LinkerFlavor::Ptx {
-        cmd.arg("--fallback-arch");
-        cmd.arg(&codegen_results.crate_info.target_cpu);
+        cmd.link_args(&["--fallback-arch", &codegen_results.crate_info.target_cpu]);
     } else if flavor == LinkerFlavor::Bpf {
-        cmd.arg("--cpu");
-        cmd.arg(&codegen_results.crate_info.target_cpu);
+        cmd.link_args(&["--cpu", &codegen_results.crate_info.target_cpu]);
         if let Some(feat) = [sess.opts.cg.target_feature.as_str(), &sess.target.options.features]
             .into_iter()
             .find(|feat| !feat.is_empty())
         {
-            cmd.arg("--cpu-features");
-            cmd.arg(feat);
+            cmd.link_args(&["--cpu-features", feat]);
         }
     }
 
@@ -2618,7 +2618,11 @@ fn add_native_libs_from_crate(
             NativeLibKind::WasmImportModule => {}
             NativeLibKind::LinkArg => {
                 if link_static {
-                    cmd.linker_arg(OsStr::new(name), verbatim);
+                    if verbatim {
+                        cmd.verbatim_arg(name);
+                    } else {
+                        cmd.link_arg(name);
+                    }
                 }
             }
         }
@@ -2813,6 +2817,15 @@ fn rehome_sysroot_lib_dir(sess: &Session, lib_dir: &Path) -> PathBuf {
     }
 }
 
+fn rehome_lib_path(sess: &Session, path: &Path) -> PathBuf {
+    if let Some(dir) = path.parent() {
+        let file_name = path.file_name().expect("library path has no file name component");
+        rehome_sysroot_lib_dir(sess, dir).join(file_name)
+    } else {
+        fix_windows_verbatim_for_gcc(path)
+    }
+}
+
 // Adds the static "rlib" versions of all crates to the command line.
 // There's a bit of magic which happens here specifically related to LTO,
 // namely that we remove upstream object files.
@@ -2843,15 +2856,8 @@ fn add_static_crate(
     let src = &codegen_results.crate_info.used_crate_source[&cnum];
     let cratepath = &src.rlib.as_ref().unwrap().0;
 
-    let mut link_upstream = |path: &Path| {
-        let rlib_path = if let Some(dir) = path.parent() {
-            let file_name = path.file_name().expect("rlib path has no file name path component");
-            rehome_sysroot_lib_dir(sess, dir).join(file_name)
-        } else {
-            fix_windows_verbatim_for_gcc(path)
-        };
-        cmd.link_staticlib_by_path(&rlib_path, false);
-    };
+    let mut link_upstream =
+        |path: &Path| cmd.link_staticlib_by_path(&rehome_lib_path(sess, path), false);
 
     if !are_upstream_rust_objects_already_included(sess)
         || ignored_for_lto(sess, &codegen_results.crate_info, cnum)
@@ -2915,27 +2921,7 @@ fn add_static_crate(
 
 // Same thing as above, but for dynamic crates instead of static crates.
 fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
-    // Just need to tell the linker about where the library lives and
-    // what its name is
-    let parent = cratepath.parent();
-    // When producing a dll, the MSVC linker may not actually emit a
-    // `foo.lib` file if the dll doesn't actually export any symbols, so we
-    // check to see if the file is there and just omit linking to it if it's
-    // not present.
-    if sess.target.is_like_msvc && !cratepath.with_extension("dll.lib").exists() {
-        return;
-    }
-    if let Some(dir) = parent {
-        cmd.include_path(&rehome_sysroot_lib_dir(sess, dir));
-    }
-    // "<dir>/name.dll -> name.dll" on windows-msvc
-    // "<dir>/name.dll -> name" on windows-gnu
-    // "<dir>/libname.<ext> -> name" elsewhere
-    let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() };
-    let stem = stem.unwrap().to_str().unwrap();
-    // Convert library file-stem into a cc -l argument.
-    let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 };
-    cmd.link_dylib_by_name(&stem[prefix..], false, true);
+    cmd.link_dylib_by_path(&rehome_lib_path(sess, cratepath), true);
 }
 
 fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
@@ -3012,10 +2998,10 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
             // This is admittedly a bit strange, as on most targets
             // `-isysroot` only applies to include header files, but on Apple
             // targets this also applies to libraries and frameworks.
-            cmd.args(&["-isysroot", &sdk_root]);
+            cmd.cc_args(&["-isysroot", &sdk_root]);
         }
         LinkerFlavor::Darwin(Cc::No, _) => {
-            cmd.args(&["-syslibroot", &sdk_root]);
+            cmd.link_args(&["-syslibroot", &sdk_root]);
         }
         _ => unreachable!(),
     }
@@ -3026,8 +3012,9 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         // search path.
 
         // The flags are called `-L` and `-F` both in Clang, ld64 and ldd.
-        cmd.arg(format!("-L{sdk_root}/System/iOSSupport/usr/lib"));
-        cmd.arg(format!("-F{sdk_root}/System/iOSSupport/System/Library/Frameworks"));
+        let sdk_root = Path::new(&sdk_root);
+        cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib"));
+        cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"));
     }
 }
 
@@ -3142,7 +3129,7 @@ fn add_lld_args(
         for path in sess.get_tools_search_paths(false) {
             let linker_path = path.join("gcc-ld");
             linker_path_exists |= linker_path.exists();
-            cmd.arg({
+            cmd.cc_arg({
                 let mut arg = OsString::from("-B");
                 arg.push(linker_path);
                 arg
@@ -3162,7 +3149,7 @@ fn add_lld_args(
     // is to use LLD but the `wasm32-wasip2` target relies on a wrapper around
     // this, `wasm-component-ld`, which is overridden if this option is passed.
     if !sess.target.is_like_wasm {
-        cmd.arg("-fuse-ld=lld");
+        cmd.cc_arg("-fuse-ld=lld");
     }
 
     if !flavor.is_gnu() {
@@ -3186,7 +3173,7 @@ fn add_lld_args(
         // targeting a different linker flavor on macOS, and that's also always
         // the case when targeting WASM.
         if sess.target.linker_flavor != sess.host.linker_flavor {
-            cmd.arg(format!("--target={}", sess.target.llvm_target));
+            cmd.cc_arg(format!("--target={}", sess.target.llvm_target));
         }
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index a82478900b1..2bd5dfdce83 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -8,7 +8,7 @@ use std::fs::{self, File};
 use std::io::prelude::*;
 use std::io::{self, BufWriter};
 use std::path::{Path, PathBuf};
-use std::{env, mem, str};
+use std::{env, iter, mem, str};
 
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::find_native_static_library;
@@ -159,6 +159,102 @@ pub fn get_linker<'a>(
     }
 }
 
+// Note: Ideally neither these helper function, nor the macro-generated inherent methods below
+// would exist, and these functions would live in `trait Linker`.
+// Unfortunately, adding these functions to `trait Linker` make it `dyn`-incompatible.
+// If the methods are added to the trait with `where Self: Sized` bounds, then even a separate
+// implementation of them for `dyn Linker {}` wouldn't work due to a conflict with those
+// uncallable methods in the trait.
+
+/// Just pass the arguments to the linker as is.
+/// It is assumed that they are correctly prepared in advance.
+fn verbatim_args<L: Linker + ?Sized>(
+    l: &mut L,
+    args: impl IntoIterator<Item: AsRef<OsStr>>,
+) -> &mut L {
+    for arg in args {
+        l.cmd().arg(arg);
+    }
+    l
+}
+/// Arguments for the underlying linker.
+/// Add options to pass them through cc wrapper if `Linker` is a cc wrapper.
+fn link_args<L: Linker + ?Sized>(
+    l: &mut L,
+    args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>,
+) -> &mut L {
+    let args = args.into_iter();
+    if !l.is_cc() {
+        verbatim_args(l, args);
+    } else if args.len() != 0 {
+        // FIXME: Support arguments with commas, see `rpaths_to_flags` for the example.
+        let mut combined_arg = OsString::from("-Wl");
+        for arg in args {
+            combined_arg.push(",");
+            combined_arg.push(arg);
+        }
+        l.cmd().arg(combined_arg);
+    }
+    l
+}
+/// Arguments for the cc wrapper specifically.
+/// Check that it's indeed a cc wrapper and pass verbatim.
+fn cc_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
+    assert!(l.is_cc());
+    verbatim_args(l, args)
+}
+/// Arguments supported by both underlying linker and cc wrapper, pass verbatim.
+fn link_or_cc_args<L: Linker + ?Sized>(
+    l: &mut L,
+    args: impl IntoIterator<Item: AsRef<OsStr>>,
+) -> &mut L {
+    verbatim_args(l, args)
+}
+
+macro_rules! generate_arg_methods {
+    ($($ty:ty)*) => { $(
+        impl $ty {
+            pub fn verbatim_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
+                verbatim_args(self, args)
+            }
+            pub fn verbatim_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
+                verbatim_args(self, iter::once(arg))
+            }
+            pub fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>) -> &mut Self {
+                link_args(self, args)
+            }
+            pub fn link_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
+                link_args(self, iter::once(arg))
+            }
+            pub fn cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
+                cc_args(self, args)
+            }
+            pub fn cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
+                cc_args(self, iter::once(arg))
+            }
+            pub fn link_or_cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
+                link_or_cc_args(self, args)
+            }
+            pub fn link_or_cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
+                link_or_cc_args(self, iter::once(arg))
+            }
+        }
+    )* }
+}
+
+generate_arg_methods! {
+    GccLinker<'_>
+    MsvcLinker<'_>
+    EmLinker<'_>
+    WasmLd<'_>
+    L4Bender<'_>
+    AixLinker<'_>
+    LlbcLinker<'_>
+    PtxLinker<'_>
+    BpfLinker<'_>
+    dyn Linker + '_
+}
+
 /// Linker abstraction used by `back::link` to build up the command to invoke a
 /// linker.
 ///
@@ -168,17 +264,33 @@ pub fn get_linker<'a>(
 /// MSVC linker (e.g., `link.exe`) is being used.
 pub trait Linker {
     fn cmd(&mut self) -> &mut Command;
+    fn is_cc(&self) -> bool {
+        false
+    }
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
-    fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool);
+    fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
+        bug!("dylib linked with unsupported linker")
+    }
+    fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool) {
+        bug!("dylib linked with unsupported linker")
+    }
     fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
         bug!("framework linked with unsupported linker")
     }
     fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool);
     fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool);
-    fn include_path(&mut self, path: &Path);
-    fn framework_path(&mut self, path: &Path);
-    fn output_filename(&mut self, path: &Path);
-    fn add_object(&mut self, path: &Path);
+    fn include_path(&mut self, path: &Path) {
+        link_or_cc_args(link_or_cc_args(self, &["-L"]), &[path]);
+    }
+    fn framework_path(&mut self, _path: &Path) {
+        bug!("framework path set with unsupported linker")
+    }
+    fn output_filename(&mut self, path: &Path) {
+        link_or_cc_args(link_or_cc_args(self, &["-o"]), &[path]);
+    }
+    fn add_object(&mut self, path: &Path) {
+        link_or_cc_args(self, &[path]);
+    }
     fn gc_sections(&mut self, keep_metadata: bool);
     fn no_gc_sections(&mut self);
     fn full_relro(&mut self);
@@ -198,25 +310,9 @@ pub trait Linker {
     fn add_no_exec(&mut self) {}
     fn add_as_needed(&mut self) {}
     fn reset_per_library_state(&mut self) {}
-    fn linker_arg(&mut self, arg: &OsStr, verbatim: bool) {
-        self.linker_args(&[arg], verbatim);
-    }
-    fn linker_args(&mut self, args: &[&OsStr], _verbatim: bool) {
-        args.into_iter().for_each(|a| {
-            self.cmd().arg(a);
-        });
-    }
 }
 
 impl dyn Linker + '_ {
-    pub fn arg(&mut self, arg: impl AsRef<OsStr>) {
-        self.cmd().arg(arg);
-    }
-
-    pub fn args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) {
-        self.cmd().args(args);
-    }
-
     pub fn take_cmd(&mut self) -> Command {
         mem::replace(self.cmd(), Command::new(""))
     }
@@ -233,14 +329,6 @@ pub struct GccLinker<'a> {
 }
 
 impl<'a> GccLinker<'a> {
-    fn linker_arg(&mut self, arg: impl AsRef<OsStr>) {
-        Linker::linker_arg(self, arg.as_ref(), false);
-    }
-    fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) {
-        let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect();
-        Linker::linker_args(self, &args_vec, false);
-    }
-
     fn takes_hints(&self) -> bool {
         // Really this function only returns true if the underlying linker
         // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We
@@ -262,7 +350,7 @@ impl<'a> GccLinker<'a> {
             return;
         }
         if self.hinted_static != Some(true) {
-            self.linker_arg("-Bstatic");
+            self.link_arg("-Bstatic");
             self.hinted_static = Some(true);
         }
     }
@@ -272,7 +360,7 @@ impl<'a> GccLinker<'a> {
             return;
         }
         if self.hinted_static != Some(false) {
-            self.linker_arg("-Bdynamic");
+            self.link_arg("-Bdynamic");
             self.hinted_static = Some(false);
         }
     }
@@ -281,7 +369,7 @@ impl<'a> GccLinker<'a> {
         if let Some(plugin_path) = plugin_path {
             let mut arg = OsString::from("-plugin=");
             arg.push(plugin_path);
-            self.linker_arg(&arg);
+            self.link_arg(&arg);
         }
 
         let opt_level = match self.sess.opts.optimize {
@@ -292,9 +380,9 @@ impl<'a> GccLinker<'a> {
         };
 
         if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use {
-            self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
+            self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
         };
-        self.linker_args(&[
+        self.link_args(&[
             &format!("-plugin-opt={opt_level}"),
             &format!("-plugin-opt=mcpu={}", self.target_cpu),
         ]);
@@ -304,10 +392,10 @@ impl<'a> GccLinker<'a> {
         // On mac we need to tell the linker to let this library be rpathed
         if self.sess.target.is_like_osx {
             if !self.is_ld {
-                self.cmd.arg("-dynamiclib");
+                self.cc_arg("-dynamiclib");
             }
 
-            self.linker_arg("-dylib");
+            self.link_arg("-dylib");
 
             // Note that the `osx_rpath_install_name` option here is a hack
             // purely to support rustbuild right now, we should get a more
@@ -316,105 +404,110 @@ impl<'a> GccLinker<'a> {
             if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name {
                 let mut rpath = OsString::from("@rpath/");
                 rpath.push(out_filename.file_name().unwrap());
-                self.linker_args(&[OsString::from("-install_name"), rpath]);
+                self.link_arg("-install_name").link_arg(rpath);
             }
         } else {
-            self.cmd.arg("-shared");
-            if self.sess.target.is_like_windows {
-                // The output filename already contains `dll_suffix` so
-                // the resulting import library will have a name in the
-                // form of libfoo.dll.a
-                let implib_name =
-                    out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
-                        format!(
-                            "{}{}{}",
-                            self.sess.target.staticlib_prefix,
-                            file,
-                            self.sess.target.staticlib_suffix
-                        )
-                    });
-                if let Some(implib_name) = implib_name {
-                    let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
-                    if let Some(implib) = implib {
-                        self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap()));
-                    }
+            self.link_or_cc_arg("-shared");
+            if let Some(name) = out_filename.file_name() {
+                if self.sess.target.is_like_windows {
+                    // The output filename already contains `dll_suffix` so
+                    // the resulting import library will have a name in the
+                    // form of libfoo.dll.a
+                    let mut implib_name = OsString::from(&*self.sess.target.staticlib_prefix);
+                    implib_name.push(name);
+                    implib_name.push(&*self.sess.target.staticlib_suffix);
+                    let mut out_implib = OsString::from("--out-implib=");
+                    out_implib.push(out_filename.with_file_name(implib_name));
+                    self.link_arg(out_implib);
+                } else {
+                    // When dylibs are linked by a full path this value will get into `DT_NEEDED`
+                    // instead of the full path, so the library can be later found in some other
+                    // location than that specific path.
+                    let mut soname = OsString::from("-soname=");
+                    soname.push(name);
+                    self.link_arg(soname);
                 }
             }
         }
     }
-}
 
-impl<'a> Linker for GccLinker<'a> {
-    /// Passes a series of arguments directly to the linker.
-    ///
-    /// When the linker is ld-like, the arguments are simply appended to the command. When the
-    /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
-    /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
-    /// single argument is appended to the command to ensure that the order of the arguments is
-    /// preserved by the compiler.
-    fn linker_args(&mut self, args: &[&OsStr], verbatim: bool) {
-        if self.is_ld || verbatim {
-            args.into_iter().for_each(|a| {
-                self.cmd.arg(a);
-            });
-        } else {
-            if !args.is_empty() {
-                let mut s = OsString::from("-Wl");
-                for a in args {
-                    s.push(",");
-                    s.push(a);
-                }
-                self.cmd.arg(s);
+    fn with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) {
+        if !as_needed {
+            if self.sess.target.is_like_osx {
+                // FIXME(81490): ld64 doesn't support these flags but macOS 11
+                // has -needed-l{} / -needed_library {}
+                // but we have no way to detect that here.
+                self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
+            } else if self.is_gnu && !self.sess.target.is_like_windows {
+                self.link_arg("--no-as-needed");
+            } else {
+                self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier);
+            }
+        }
+
+        f(self);
+
+        if !as_needed {
+            if self.sess.target.is_like_osx {
+                // See above FIXME comment
+            } else if self.is_gnu && !self.sess.target.is_like_windows {
+                self.link_arg("--as-needed");
             }
         }
     }
+}
 
+impl<'a> Linker for GccLinker<'a> {
     fn cmd(&mut self) -> &mut Command {
         &mut self.cmd
     }
 
+    fn is_cc(&self) -> bool {
+        !self.is_ld
+    }
+
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe => {
                 if !self.is_ld && self.is_gnu {
-                    self.cmd.arg("-no-pie");
+                    self.cc_arg("-no-pie");
                 }
             }
             LinkOutputKind::DynamicPicExe => {
                 // noop on windows w/ gcc & ld, error w/ lld
                 if !self.sess.target.is_like_windows {
                     // `-pie` works for both gcc wrapper and ld.
-                    self.cmd.arg("-pie");
+                    self.link_or_cc_arg("-pie");
                 }
             }
             LinkOutputKind::StaticNoPicExe => {
                 // `-static` works for both gcc wrapper and ld.
-                self.cmd.arg("-static");
+                self.link_or_cc_arg("-static");
                 if !self.is_ld && self.is_gnu {
-                    self.cmd.arg("-no-pie");
+                    self.cc_arg("-no-pie");
                 }
             }
             LinkOutputKind::StaticPicExe => {
                 if !self.is_ld {
                     // Note that combination `-static -pie` doesn't work as expected
                     // for the gcc wrapper, `-static` in that case suppresses `-pie`.
-                    self.cmd.arg("-static-pie");
+                    self.cc_arg("-static-pie");
                 } else {
                     // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing
                     // a static pie, but currently passed because gcc and clang pass them.
                     // The former suppresses the `INTERP` ELF header specifying dynamic linker,
                     // which is otherwise implicitly injected by ld (but not lld).
                     // The latter doesn't change anything, only ensures that everything is pic.
-                    self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
+                    self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
                 }
             }
             LinkOutputKind::DynamicDylib => self.build_dylib(out_filename),
             LinkOutputKind::StaticDylib => {
-                self.cmd.arg("-static");
+                self.link_or_cc_arg("-static");
                 self.build_dylib(out_filename);
             }
             LinkOutputKind::WasiReactorExe => {
-                self.linker_args(&["--entry", "_initialize"]);
+                self.link_args(&["--entry", "_initialize"]);
             }
         }
         // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
@@ -430,7 +523,7 @@ impl<'a> Linker for GccLinker<'a> {
                     | LinkOutputKind::StaticDylib
             )
         {
-            self.cmd.arg("--static-crt");
+            self.cc_arg("--static-crt");
         }
     }
 
@@ -443,27 +536,18 @@ impl<'a> Linker for GccLinker<'a> {
             // to the linker.
             return;
         }
-        if !as_needed {
-            if self.sess.target.is_like_osx {
-                // FIXME(81490): ld64 doesn't support these flags but macOS 11
-                // has -needed-l{} / -needed_library {}
-                // but we have no way to detect that here.
-                self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
-            } else if self.is_gnu && !self.sess.target.is_like_windows {
-                self.linker_arg("--no-as-needed");
-            } else {
-                self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier);
-            }
-        }
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },));
-        if !as_needed {
-            if self.sess.target.is_like_osx {
-                // See above FIXME comment
-            } else if self.is_gnu && !self.sess.target.is_like_windows {
-                self.linker_arg("--as-needed");
-            }
-        }
+        self.with_as_needed(as_needed, |this| {
+            let colon = if verbatim && this.is_gnu { ":" } else { "" };
+            this.link_or_cc_arg(format!("-l{colon}{name}"));
+        });
+    }
+
+    fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) {
+        self.hint_dynamic();
+        self.with_as_needed(as_needed, |this| {
+            this.link_or_cc_arg(path);
+        })
     }
 
     fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
@@ -471,63 +555,51 @@ impl<'a> Linker for GccLinker<'a> {
         if !as_needed {
             // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
             // flag but we have no way to detect that here.
-            // self.cmd.arg("-needed_framework").arg(name);
+            // self.link_or_cc_arg("-needed_framework").link_or_cc_arg(name);
             self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
         }
-        self.cmd.arg("-framework").arg(name);
+        self.link_or_cc_args(&["-framework", name]);
     }
 
     fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
         self.hint_static();
         let colon = if verbatim && self.is_gnu { ":" } else { "" };
         if !whole_archive {
-            self.cmd.arg(format!("-l{colon}{name}"));
+            self.link_or_cc_arg(format!("-l{colon}{name}"));
         } else if self.sess.target.is_like_osx {
             // -force_load is the macOS equivalent of --whole-archive, but it
             // involves passing the full path to the library to link.
-            self.linker_arg("-force_load");
-            self.linker_arg(find_native_static_library(name, verbatim, self.sess));
+            self.link_arg("-force_load");
+            self.link_arg(find_native_static_library(name, verbatim, self.sess));
         } else {
-            self.linker_arg("--whole-archive");
-            self.cmd.arg(format!("-l{colon}{name}"));
-            self.linker_arg("--no-whole-archive");
+            self.link_arg("--whole-archive")
+                .link_or_cc_arg(format!("-l{colon}{name}"))
+                .link_arg("--no-whole-archive");
         }
     }
 
     fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
         self.hint_static();
         if !whole_archive {
-            self.cmd.arg(path);
+            self.link_or_cc_arg(path);
         } else if self.sess.target.is_like_osx {
-            self.linker_arg("-force_load");
-            self.linker_arg(path);
+            self.link_arg("-force_load").link_arg(path);
         } else {
-            self.linker_arg("--whole-archive");
-            self.linker_arg(path);
-            self.linker_arg("--no-whole-archive");
+            self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive");
         }
     }
 
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
-    }
     fn framework_path(&mut self, path: &Path) {
-        self.cmd.arg("-F").arg(path);
-    }
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
+        self.link_or_cc_arg("-F").link_or_cc_arg(path);
     }
     fn full_relro(&mut self) {
-        self.linker_args(&["-z", "relro", "-z", "now"]);
+        self.link_args(&["-z", "relro", "-z", "now"]);
     }
     fn partial_relro(&mut self) {
-        self.linker_args(&["-z", "relro"]);
+        self.link_args(&["-z", "relro"]);
     }
     fn no_relro(&mut self) {
-        self.linker_args(&["-z", "norelro"]);
+        self.link_args(&["-z", "norelro"]);
     }
 
     fn gc_sections(&mut self, keep_metadata: bool) {
@@ -546,7 +618,7 @@ impl<'a> Linker for GccLinker<'a> {
         // for partial linking when using multiple codegen units (-r). So we
         // insert it here.
         if self.sess.target.is_like_osx {
-            self.linker_arg("-dead_strip");
+            self.link_arg("-dead_strip");
 
         // If we're building a dylib, we don't use --gc-sections because LLVM
         // has already done the best it can do, and we also don't want to
@@ -554,13 +626,13 @@ impl<'a> Linker for GccLinker<'a> {
         // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
         // reduction.
         } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata {
-            self.linker_arg("--gc-sections");
+            self.link_arg("--gc-sections");
         }
     }
 
     fn no_gc_sections(&mut self) {
         if self.is_gnu || self.sess.target.is_like_wasm {
-            self.linker_arg("--no-gc-sections");
+            self.link_arg("--no-gc-sections");
         }
     }
 
@@ -574,7 +646,7 @@ impl<'a> Linker for GccLinker<'a> {
         if self.sess.opts.optimize == config::OptLevel::Default
             || self.sess.opts.optimize == config::OptLevel::Aggressive
         {
-            self.linker_arg("-O1");
+            self.link_arg("-O1");
         }
     }
 
@@ -594,8 +666,7 @@ impl<'a> Linker for GccLinker<'a> {
         //
         // Though it may be worth to try to revert those changes upstream, since
         // the overhead of the initialization should be minor.
-        self.cmd.arg("-u");
-        self.cmd.arg("__llvm_profile_runtime");
+        self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]);
     }
 
     fn control_flow_guard(&mut self) {}
@@ -616,33 +687,33 @@ impl<'a> Linker for GccLinker<'a> {
                 // The --strip-debug case is handled by running an external
                 // `strip` utility as a separate step after linking.
                 if !self.sess.target.is_like_solaris {
-                    self.linker_arg("--strip-debug");
+                    self.link_arg("--strip-debug");
                 }
             }
             Strip::Symbols => {
-                self.linker_arg("--strip-all");
+                self.link_arg("--strip-all");
             }
         }
         match self.sess.opts.unstable_opts.debuginfo_compression {
             config::DebugInfoCompression::None => {}
             config::DebugInfoCompression::Zlib => {
-                self.linker_arg("--compress-debug-sections=zlib");
+                self.link_arg("--compress-debug-sections=zlib");
             }
             config::DebugInfoCompression::Zstd => {
-                self.linker_arg("--compress-debug-sections=zstd");
+                self.link_arg("--compress-debug-sections=zstd");
             }
         }
     }
 
     fn no_crt_objects(&mut self) {
         if !self.is_ld {
-            self.cmd.arg("-nostartfiles");
+            self.cc_arg("-nostartfiles");
         }
     }
 
     fn no_default_libraries(&mut self) {
         if !self.is_ld {
-            self.cmd.arg("-nodefaultlibs");
+            self.cc_arg("-nodefaultlibs");
         }
     }
 
@@ -718,24 +789,22 @@ impl<'a> Linker for GccLinker<'a> {
         }
 
         if self.sess.target.is_like_osx {
-            self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]);
+            self.link_arg("-exported_symbols_list").link_arg(path);
         } else if self.sess.target.is_like_solaris {
-            self.linker_args(&[OsString::from("-M"), path.into()]);
+            self.link_arg("-M").link_arg(path);
         } else {
             if is_windows {
-                self.linker_arg(path);
+                self.link_arg(path);
             } else {
                 let mut arg = OsString::from("--version-script=");
                 arg.push(path);
-                self.linker_arg(arg);
-                self.linker_arg("--no-undefined-version");
+                self.link_arg(arg).link_arg("--no-undefined-version");
             }
         }
     }
 
     fn subsystem(&mut self, subsystem: &str) {
-        self.linker_arg("--subsystem");
-        self.linker_arg(&subsystem);
+        self.link_args(&["--subsystem", subsystem]);
     }
 
     fn reset_per_library_state(&mut self) {
@@ -760,23 +829,23 @@ impl<'a> Linker for GccLinker<'a> {
     // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't,
     // so we just always add it.
     fn add_eh_frame_header(&mut self) {
-        self.linker_arg("--eh-frame-hdr");
+        self.link_arg("--eh-frame-hdr");
     }
 
     fn add_no_exec(&mut self) {
         if self.sess.target.is_like_windows {
-            self.linker_arg("--nxcompat");
+            self.link_arg("--nxcompat");
         } else if self.is_gnu {
-            self.linker_args(&["-z", "noexecstack"]);
+            self.link_args(&["-z", "noexecstack"]);
         }
     }
 
     fn add_as_needed(&mut self) {
         if self.is_gnu && !self.sess.target.is_like_windows {
-            self.linker_arg("--as-needed");
+            self.link_arg("--as-needed");
         } else if self.sess.target.is_like_solaris {
             // -z ignore is the Solaris equivalent to the GNU ld --as-needed option
-            self.linker_args(&["-z", "ignore"]);
+            self.link_args(&["-z", "ignore"]);
         }
     }
 }
@@ -798,10 +867,10 @@ impl<'a> Linker for MsvcLinker<'a> {
             | LinkOutputKind::StaticNoPicExe
             | LinkOutputKind::StaticPicExe => {}
             LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
-                self.cmd.arg("/DLL");
+                self.link_arg("/DLL");
                 let mut arg: OsString = "/IMPLIB:".into();
                 arg.push(out_filename.with_extension("dll.lib"));
-                self.cmd.arg(arg);
+                self.link_arg(arg);
             }
             LinkOutputKind::WasiReactorExe => {
                 panic!("can't link as reactor on non-wasi target");
@@ -810,44 +879,49 @@ impl<'a> Linker for MsvcLinker<'a> {
     }
 
     fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
-        self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
+        self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
+    }
+
+    fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
+        // When producing a dll, MSVC linker may not emit an implib file if the dll doesn't export
+        // any symbols, so we skip linking if the implib file is not present.
+        let implib_path = path.with_extension("dll.lib");
+        if implib_path.exists() {
+            self.link_or_cc_arg(implib_path);
+        }
     }
 
     fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
         let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
         let suffix = if verbatim { "" } else { ".lib" };
-        self.cmd.arg(format!("{prefix}{name}{suffix}"));
+        self.link_arg(format!("{prefix}{name}{suffix}"));
     }
 
     fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
         if !whole_archive {
-            self.cmd.arg(path);
+            self.link_arg(path);
         } else {
             let mut arg = OsString::from("/WHOLEARCHIVE:");
             arg.push(path);
-            self.cmd.arg(arg);
+            self.link_arg(arg);
         }
     }
 
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
-    }
-
     fn gc_sections(&mut self, _keep_metadata: bool) {
         // MSVC's ICF (Identical COMDAT Folding) link optimization is
         // slow for Rust and thus we disable it by default when not in
         // optimization build.
         if self.sess.opts.optimize != config::OptLevel::No {
-            self.cmd.arg("/OPT:REF,ICF");
+            self.link_arg("/OPT:REF,ICF");
         } else {
             // It is necessary to specify NOICF here, because /OPT:REF
             // implies ICF by default.
-            self.cmd.arg("/OPT:REF,NOICF");
+            self.link_arg("/OPT:REF,NOICF");
         }
     }
 
     fn no_gc_sections(&mut self) {
-        self.cmd.arg("/OPT:NOREF,NOICF");
+        self.link_arg("/OPT:NOREF,NOICF");
     }
 
     fn full_relro(&mut self) {
@@ -867,23 +941,19 @@ impl<'a> Linker for MsvcLinker<'a> {
     }
 
     fn no_default_libraries(&mut self) {
-        self.cmd.arg("/NODEFAULTLIB");
+        self.link_arg("/NODEFAULTLIB");
     }
 
     fn include_path(&mut self, path: &Path) {
         let mut arg = OsString::from("/LIBPATH:");
         arg.push(path);
-        self.cmd.arg(&arg);
+        self.link_arg(&arg);
     }
 
     fn output_filename(&mut self, path: &Path) {
         let mut arg = OsString::from("/OUT:");
         arg.push(path);
-        self.cmd.arg(&arg);
-    }
-
-    fn framework_path(&mut self, _path: &Path) {
-        bug!("frameworks are not supported on windows")
+        self.link_arg(&arg);
     }
 
     fn optimize(&mut self) {
@@ -895,19 +965,19 @@ impl<'a> Linker for MsvcLinker<'a> {
     }
 
     fn control_flow_guard(&mut self) {
-        self.cmd.arg("/guard:cf");
+        self.link_arg("/guard:cf");
     }
 
     fn ehcont_guard(&mut self) {
         if self.sess.target.pointer_width == 64 {
-            self.cmd.arg("/guard:ehcont");
+            self.link_arg("/guard:ehcont");
         }
     }
 
     fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
         // This will cause the Microsoft linker to generate a PDB file
         // from the CodeView line tables in the object files.
-        self.cmd.arg("/DEBUG");
+        self.link_arg("/DEBUG");
 
         // Default to emitting only the file name of the PDB file into
         // the binary instead of the full path. Emitting the full path
@@ -916,7 +986,7 @@ impl<'a> Linker for MsvcLinker<'a> {
         //
         // This default behavior can be overridden by explicitly passing
         // `-Clink-arg=/PDBALTPATH:...` to rustc.
-        self.cmd.arg("/PDBALTPATH:%_PDB%");
+        self.link_arg("/PDBALTPATH:%_PDB%");
 
         // This will cause the Microsoft linker to embed .natvis info into the PDB file
         let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
@@ -928,7 +998,7 @@ impl<'a> Linker for MsvcLinker<'a> {
                         if path.extension() == Some("natvis".as_ref()) {
                             let mut arg = OsString::from("/NATVIS:");
                             arg.push(path);
-                            self.cmd.arg(arg);
+                            self.link_arg(arg);
                         }
                     }
                     Err(error) => {
@@ -942,7 +1012,7 @@ impl<'a> Linker for MsvcLinker<'a> {
         for path in natvis_debugger_visualizers {
             let mut arg = OsString::from("/NATVIS:");
             arg.push(path);
-            self.cmd.arg(arg);
+            self.link_arg(arg);
         }
     }
 
@@ -986,13 +1056,13 @@ impl<'a> Linker for MsvcLinker<'a> {
         }
         let mut arg = OsString::from("/DEF:");
         arg.push(path);
-        self.cmd.arg(&arg);
+        self.link_arg(&arg);
     }
 
     fn subsystem(&mut self, subsystem: &str) {
         // Note that previous passes of the compiler validated this subsystem,
         // so we just blindly pass it to the linker.
-        self.cmd.arg(&format!("/SUBSYSTEM:{subsystem}"));
+        self.link_arg(&format!("/SUBSYSTEM:{subsystem}"));
 
         // Windows has two subsystems we're interested in right now, the console
         // and windows subsystems. These both implicitly have different entry
@@ -1009,7 +1079,7 @@ impl<'a> Linker for MsvcLinker<'a> {
         //
         // For more information see RFC #1665
         if subsystem == "windows" {
-            self.cmd.arg("/ENTRY:mainCRTStartup");
+            self.link_arg("/ENTRY:mainCRTStartup");
         }
     }
 
@@ -1018,7 +1088,7 @@ impl<'a> Linker for MsvcLinker<'a> {
     }
 
     fn add_no_exec(&mut self) {
-        self.cmd.arg("/NXCOMPAT");
+        self.link_arg("/NXCOMPAT");
     }
 }
 
@@ -1032,31 +1102,27 @@ impl<'a> Linker for EmLinker<'a> {
         &mut self.cmd
     }
 
+    fn is_cc(&self) -> bool {
+        true
+    }
+
     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
 
     fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
         // Emscripten always links statically
-        self.cmd.arg("-l").arg(name);
+        self.link_or_cc_args(&["-l", name]);
     }
 
-    fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) {
-        self.cmd.arg("-l").arg(name);
+    fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
+        self.link_or_cc_arg(path);
     }
 
-    fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
-        self.cmd.arg(path);
-    }
-
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
-    }
-
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
+    fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) {
+        self.link_or_cc_args(&["-l", name]);
     }
 
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
+    fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
+        self.link_or_cc_arg(path);
     }
 
     fn full_relro(&mut self) {
@@ -1071,10 +1137,6 @@ impl<'a> Linker for EmLinker<'a> {
         // noop
     }
 
-    fn framework_path(&mut self, _path: &Path) {
-        bug!("frameworks are not supported on Emscripten")
-    }
-
     fn gc_sections(&mut self, _keep_metadata: bool) {
         // noop
     }
@@ -1085,7 +1147,7 @@ impl<'a> Linker for EmLinker<'a> {
 
     fn optimize(&mut self) {
         // Emscripten performs own optimizations
-        self.cmd.arg(match self.sess.opts.optimize {
+        self.cc_arg(match self.sess.opts.optimize {
             OptLevel::No => "-O0",
             OptLevel::Less => "-O1",
             OptLevel::Default => "-O2",
@@ -1106,7 +1168,7 @@ impl<'a> Linker for EmLinker<'a> {
     fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
         // Preserve names or generate source maps depending on debug info
         // For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g
-        self.cmd.arg(match self.sess.opts.debuginfo {
+        self.cc_arg(match self.sess.opts.debuginfo {
             DebugInfo::None => "-g0",
             DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => {
                 "--profiling-funcs"
@@ -1118,13 +1180,13 @@ impl<'a> Linker for EmLinker<'a> {
     fn no_crt_objects(&mut self) {}
 
     fn no_default_libraries(&mut self) {
-        self.cmd.arg("-nodefaultlibs");
+        self.cc_arg("-nodefaultlibs");
     }
 
     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
         debug!("EXPORTED SYMBOLS:");
 
-        self.cmd.arg("-s");
+        self.cc_arg("-s");
 
         let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
         let encoded = serde_json::to_string(
@@ -1135,7 +1197,7 @@ impl<'a> Linker for EmLinker<'a> {
 
         arg.push(encoded);
 
-        self.cmd.arg(arg);
+        self.cc_arg(arg);
     }
 
     fn subsystem(&mut self, _subsystem: &str) {
@@ -1153,7 +1215,7 @@ pub struct WasmLd<'a> {
 }
 
 impl<'a> WasmLd<'a> {
-    fn new(mut cmd: Command, sess: &'a Session) -> WasmLd<'a> {
+    fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> {
         // If the atomics feature is enabled for wasm then we need a whole bunch
         // of flags:
         //
@@ -1172,18 +1234,19 @@ impl<'a> WasmLd<'a> {
         // On wasm32-unknown-unknown, we also export symbols for glue code to use:
         //    * `--export=*tls*` - when `#[thread_local]` symbols are used these
         //      symbols are how the TLS segments are initialized and configured.
+        let mut wasm_ld = WasmLd { cmd, sess };
         if sess.target_features.contains(&sym::atomics) {
-            cmd.arg("--shared-memory");
-            cmd.arg("--max-memory=1073741824");
-            cmd.arg("--import-memory");
+            wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
             if sess.target.os == "unknown" {
-                cmd.arg("--export=__wasm_init_tls");
-                cmd.arg("--export=__tls_size");
-                cmd.arg("--export=__tls_align");
-                cmd.arg("--export=__tls_base");
+                wasm_ld.link_args(&[
+                    "--export=__wasm_init_tls",
+                    "--export=__tls_size",
+                    "--export=__tls_align",
+                    "--export=__tls_base",
+                ]);
             }
         }
-        WasmLd { cmd, sess }
+        wasm_ld
     }
 }
 
@@ -1199,51 +1262,40 @@ impl<'a> Linker for WasmLd<'a> {
             | LinkOutputKind::StaticNoPicExe
             | LinkOutputKind::StaticPicExe => {}
             LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
-                self.cmd.arg("--no-entry");
+                self.link_arg("--no-entry");
             }
             LinkOutputKind::WasiReactorExe => {
-                self.cmd.arg("--entry");
-                self.cmd.arg("_initialize");
+                self.link_args(&["--entry", "_initialize"]);
             }
         }
     }
 
     fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
-        self.cmd.arg("-l").arg(name);
+        self.link_or_cc_args(&["-l", name]);
+    }
+
+    fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
+        self.link_or_cc_arg(path);
     }
 
     fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
         if !whole_archive {
-            self.cmd.arg("-l").arg(name);
+            self.link_or_cc_args(&["-l", name]);
         } else {
-            self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive");
+            self.link_arg("--whole-archive")
+                .link_or_cc_args(&["-l", name])
+                .link_arg("--no-whole-archive");
         }
     }
 
     fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
         if !whole_archive {
-            self.cmd.arg(path);
+            self.link_or_cc_arg(path);
         } else {
-            self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive");
+            self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
         }
     }
 
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
-    }
-
-    fn framework_path(&mut self, _path: &Path) {
-        panic!("frameworks not supported")
-    }
-
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
-    }
-
     fn full_relro(&mut self) {}
 
     fn partial_relro(&mut self) {}
@@ -1251,17 +1303,17 @@ impl<'a> Linker for WasmLd<'a> {
     fn no_relro(&mut self) {}
 
     fn gc_sections(&mut self, _keep_metadata: bool) {
-        self.cmd.arg("--gc-sections");
+        self.link_arg("--gc-sections");
     }
 
     fn no_gc_sections(&mut self) {
-        self.cmd.arg("--no-gc-sections");
+        self.link_arg("--no-gc-sections");
     }
 
     fn optimize(&mut self) {
         // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and
         // only differentiates -O0 and -O1. It does not apply to LTO.
-        self.cmd.arg(match self.sess.opts.optimize {
+        self.link_arg(match self.sess.opts.optimize {
             OptLevel::No => "-O0",
             OptLevel::Less => "-O1",
             OptLevel::Default => "-O2",
@@ -1279,10 +1331,10 @@ impl<'a> Linker for WasmLd<'a> {
         match strip {
             Strip::None => {}
             Strip::Debuginfo => {
-                self.cmd.arg("--strip-debug");
+                self.link_arg("--strip-debug");
             }
             Strip::Symbols => {
-                self.cmd.arg("--strip-all");
+                self.link_arg("--strip-all");
             }
         }
     }
@@ -1297,7 +1349,7 @@ impl<'a> Linker for WasmLd<'a> {
 
     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
         for sym in symbols {
-            self.cmd.arg("--export").arg(&sym);
+            self.link_args(&["--export", sym]);
         }
 
         // LLD will hide these otherwise-internal symbols since it only exports
@@ -1305,8 +1357,7 @@ impl<'a> Linker for WasmLd<'a> {
         // others. Various bits and pieces of wasm32-unknown-unknown tooling use
         // this, so be sure these symbols make their way out of the linker as well.
         if self.sess.target.os == "unknown" {
-            self.cmd.arg("--export=__heap_base");
-            self.cmd.arg("--export=__data_end");
+            self.link_args(&["--export=__heap_base", "--export=__data_end"]);
         }
     }
 
@@ -1337,7 +1388,7 @@ impl<'a> WasmLd<'a> {
             // wasm-ld only handles integer LTO opt levels. Use O2
             config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
         };
-        self.cmd.arg(&format!("--lto-{opt_level}"));
+        self.link_arg(&format!("--lto-{opt_level}"));
     }
 }
 
@@ -1355,63 +1406,46 @@ impl<'a> Linker for L4Bender<'a> {
 
     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
 
-    fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
-        bug!("dylibs are not supported on L4Re");
-    }
-
     fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
         self.hint_static();
         if !whole_archive {
-            self.cmd.arg(format!("-PC{name}"));
+            self.link_arg(format!("-PC{name}"));
         } else {
-            self.cmd.arg("--whole-archive").arg(format!("-l{name}")).arg("--no-whole-archive");
+            self.link_arg("--whole-archive")
+                .link_or_cc_arg(format!("-l{name}"))
+                .link_arg("--no-whole-archive");
         }
     }
 
     fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
         self.hint_static();
         if !whole_archive {
-            self.cmd.arg(path);
+            self.link_or_cc_arg(path);
         } else {
-            self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive");
+            self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
         }
     }
 
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
-    }
-    fn framework_path(&mut self, _: &Path) {
-        bug!("frameworks are not supported on L4Re");
-    }
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
-    }
-
     fn full_relro(&mut self) {
-        self.cmd.arg("-z").arg("relro");
-        self.cmd.arg("-z").arg("now");
+        self.link_args(&["-z", "relro", "-z", "now"]);
     }
 
     fn partial_relro(&mut self) {
-        self.cmd.arg("-z").arg("relro");
+        self.link_args(&["-z", "relro"]);
     }
 
     fn no_relro(&mut self) {
-        self.cmd.arg("-z").arg("norelro");
+        self.link_args(&["-z", "norelro"]);
     }
 
     fn gc_sections(&mut self, keep_metadata: bool) {
         if !keep_metadata {
-            self.cmd.arg("--gc-sections");
+            self.link_arg("--gc-sections");
         }
     }
 
     fn no_gc_sections(&mut self) {
-        self.cmd.arg("--no-gc-sections");
+        self.link_arg("--no-gc-sections");
     }
 
     fn optimize(&mut self) {
@@ -1420,7 +1454,7 @@ impl<'a> Linker for L4Bender<'a> {
         if self.sess.opts.optimize == config::OptLevel::Default
             || self.sess.opts.optimize == config::OptLevel::Aggressive
         {
-            self.cmd.arg("-O1");
+            self.link_arg("-O1");
         }
     }
 
@@ -1430,16 +1464,16 @@ impl<'a> Linker for L4Bender<'a> {
         match strip {
             Strip::None => {}
             Strip::Debuginfo => {
-                self.cmd().arg("--strip-debug");
+                self.link_arg("--strip-debug");
             }
             Strip::Symbols => {
-                self.cmd().arg("--strip-all");
+                self.link_arg("--strip-all");
             }
         }
     }
 
     fn no_default_libraries(&mut self) {
-        self.cmd.arg("-nostdlib");
+        self.cc_arg("-nostdlib");
     }
 
     fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
@@ -1449,7 +1483,7 @@ impl<'a> Linker for L4Bender<'a> {
     }
 
     fn subsystem(&mut self, subsystem: &str) {
-        self.cmd.arg(&format!("--subsystem {subsystem}"));
+        self.link_arg(&format!("--subsystem {subsystem}"));
     }
 
     fn reset_per_library_state(&mut self) {
@@ -1467,12 +1501,12 @@ impl<'a> Linker for L4Bender<'a> {
 
 impl<'a> L4Bender<'a> {
     pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
-        L4Bender { cmd: cmd, sess: sess, hinted_static: false }
+        L4Bender { cmd, sess: sess, hinted_static: false }
     }
 
     fn hint_static(&mut self) {
         if !self.hinted_static {
-            self.cmd.arg("-static");
+            self.link_or_cc_arg("-static");
             self.hinted_static = true;
         }
     }
@@ -1487,29 +1521,28 @@ pub struct AixLinker<'a> {
 
 impl<'a> AixLinker<'a> {
     pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
-        AixLinker { cmd: cmd, sess: sess, hinted_static: None }
+        AixLinker { cmd, sess: sess, hinted_static: None }
     }
 
     fn hint_static(&mut self) {
         if self.hinted_static != Some(true) {
-            self.cmd.arg("-bstatic");
+            self.link_arg("-bstatic");
             self.hinted_static = Some(true);
         }
     }
 
     fn hint_dynamic(&mut self) {
         if self.hinted_static != Some(false) {
-            self.cmd.arg("-bdynamic");
+            self.link_arg("-bdynamic");
             self.hinted_static = Some(false);
         }
     }
 
     fn build_dylib(&mut self, _out_filename: &Path) {
-        self.cmd.arg("-bM:SRE");
-        self.cmd.arg("-bnoentry");
+        self.link_args(&["-bM:SRE", "-bnoentry"]);
         // FIXME: Use CreateExportList utility to create export list
         // and remove -bexpfull.
-        self.cmd.arg("-bexpfull");
+        self.link_arg("-bexpfull");
     }
 }
 
@@ -1534,47 +1567,36 @@ impl<'a> Linker for AixLinker<'a> {
 
     fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{name}"));
+        self.link_or_cc_arg(format!("-l{name}"));
+    }
+
+    fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
+        self.hint_dynamic();
+        self.link_or_cc_arg(path);
     }
 
     fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
         self.hint_static();
         if !whole_archive {
-            self.cmd.arg(format!("-l{name}"));
+            self.link_or_cc_arg(format!("-l{name}"));
         } else {
             let mut arg = OsString::from("-bkeepfile:");
             arg.push(find_native_static_library(name, verbatim, self.sess));
-            self.cmd.arg(arg);
+            self.link_or_cc_arg(arg);
         }
     }
 
     fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
         self.hint_static();
         if !whole_archive {
-            self.cmd.arg(path);
+            self.link_or_cc_arg(path);
         } else {
             let mut arg = OsString::from("-bkeepfile:");
             arg.push(path);
-            self.cmd.arg(arg);
+            self.link_arg(arg);
         }
     }
 
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
-    }
-
-    fn framework_path(&mut self, _: &Path) {
-        bug!("frameworks are not supported on AIX");
-    }
-
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
-    }
-
     fn full_relro(&mut self) {}
 
     fn partial_relro(&mut self) {}
@@ -1582,17 +1604,17 @@ impl<'a> Linker for AixLinker<'a> {
     fn no_relro(&mut self) {}
 
     fn gc_sections(&mut self, _keep_metadata: bool) {
-        self.cmd.arg("-bgc");
+        self.link_arg("-bgc");
     }
 
     fn no_gc_sections(&mut self) {
-        self.cmd.arg("-bnogc");
+        self.link_arg("-bnogc");
     }
 
     fn optimize(&mut self) {}
 
     fn pgo_gen(&mut self) {
-        self.cmd.arg("-bdbg:namedsects:ss");
+        self.link_arg("-bdbg:namedsects:ss");
     }
 
     fn control_flow_guard(&mut self) {}
@@ -1618,7 +1640,7 @@ impl<'a> Linker for AixLinker<'a> {
         if let Err(e) = res {
             self.sess.dcx().fatal(format!("failed to write export file: {e}"));
         }
-        self.cmd.arg(format!("-bE:{}", path.to_str().unwrap()));
+        self.link_arg(format!("-bE:{}", path.to_str().unwrap()));
     }
 
     fn subsystem(&mut self, _subsystem: &str) {}
@@ -1738,48 +1760,32 @@ impl<'a> Linker for PtxLinker<'a> {
 
     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
 
-    fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
-        panic!("external dylibs not supported")
-    }
-
     fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
     }
 
     fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
-        self.cmd.arg("--rlib").arg(path);
-    }
-
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
+        self.link_arg("--rlib").link_arg(path);
     }
 
     fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
-        self.cmd.arg("--debug");
+        self.link_arg("--debug");
     }
 
     fn add_object(&mut self, path: &Path) {
-        self.cmd.arg("--bitcode").arg(path);
+        self.link_arg("--bitcode").link_arg(path);
     }
 
     fn optimize(&mut self) {
         match self.sess.lto() {
             Lto::Thin | Lto::Fat | Lto::ThinLocal => {
-                self.cmd.arg("-Olto");
+                self.link_arg("-Olto");
             }
 
             Lto::No => {}
         }
     }
 
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-
-    fn framework_path(&mut self, _path: &Path) {
-        panic!("frameworks not supported")
-    }
-
     fn full_relro(&mut self) {}
 
     fn partial_relro(&mut self) {}
@@ -1820,28 +1826,16 @@ impl<'a> Linker for LlbcLinker<'a> {
 
     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
 
-    fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
-        panic!("external dylibs not supported")
-    }
-
     fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
     }
 
     fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
-        self.cmd.arg(path);
-    }
-
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
+        self.link_or_cc_arg(path);
     }
 
     fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
-        self.cmd.arg("--debug");
-    }
-
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
+        self.link_arg("--debug");
     }
 
     fn optimize(&mut self) {
@@ -1855,14 +1849,6 @@ impl<'a> Linker for LlbcLinker<'a> {
         };
     }
 
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-
-    fn framework_path(&mut self, _path: &Path) {
-        panic!("frameworks not supported")
-    }
-
     fn full_relro(&mut self) {}
 
     fn partial_relro(&mut self) {}
@@ -1887,7 +1873,7 @@ impl<'a> Linker for LlbcLinker<'a> {
         match _crate_type {
             CrateType::Cdylib => {
                 for sym in symbols {
-                    self.cmd.arg("--export-symbol").arg(sym);
+                    self.link_args(&["--export-symbol", sym]);
                 }
             }
             _ => (),
@@ -1911,32 +1897,20 @@ impl<'a> Linker for BpfLinker<'a> {
 
     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
 
-    fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
-        panic!("external dylibs not supported")
-    }
-
     fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
     }
 
     fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
-        self.cmd.arg(path);
-    }
-
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
+        self.link_or_cc_arg(path);
     }
 
     fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
-        self.cmd.arg("--debug");
-    }
-
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
+        self.link_arg("--debug");
     }
 
     fn optimize(&mut self) {
-        self.cmd.arg(match self.sess.opts.optimize {
+        self.link_arg(match self.sess.opts.optimize {
             OptLevel::No => "-O0",
             OptLevel::Less => "-O1",
             OptLevel::Default => "-O2",
@@ -1946,14 +1920,6 @@ impl<'a> Linker for BpfLinker<'a> {
         });
     }
 
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-
-    fn framework_path(&mut self, _path: &Path) {
-        panic!("frameworks not supported")
-    }
-
     fn full_relro(&mut self) {}
 
     fn partial_relro(&mut self) {}
@@ -1985,7 +1951,7 @@ impl<'a> Linker for BpfLinker<'a> {
         if let Err(error) = res {
             self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error });
         } else {
-            self.cmd.arg("--export-symbols").arg(&path);
+            self.link_arg("--export-symbols").link_arg(&path);
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs
index f499bbcf853..82070d4453b 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs
@@ -9,16 +9,10 @@ pub struct RPathConfig<'a> {
     pub libs: &'a [&'a Path],
     pub out_filename: PathBuf,
     pub is_like_osx: bool,
-    pub has_rpath: bool,
     pub linker_is_gnu: bool,
 }
 
 pub fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec<OsString> {
-    // No rpath on windows
-    if !config.has_rpath {
-        return Vec::new();
-    }
-
     debug!("preparing the RPATH!");
 
     let rpaths = get_rpaths(config);
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
index 0de90a1036e..c620e92db1f 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
@@ -37,7 +37,6 @@ fn test_rpath_relative() {
     if cfg!(target_os = "macos") {
         let config = &mut RPathConfig {
             libs: &[],
-            has_rpath: true,
             is_like_osx: true,
             linker_is_gnu: false,
             out_filename: PathBuf::from("bin/rustc"),
@@ -48,7 +47,6 @@ fn test_rpath_relative() {
         let config = &mut RPathConfig {
             libs: &[],
             out_filename: PathBuf::from("bin/rustc"),
-            has_rpath: true,
             is_like_osx: false,
             linker_is_gnu: true,
         };
@@ -62,7 +60,6 @@ fn test_rpath_relative_issue_119571() {
     let config = &mut RPathConfig {
         libs: &[],
         out_filename: PathBuf::from("rustc"),
-        has_rpath: true,
         is_like_osx: false,
         linker_is_gnu: true,
     };
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index c18816533a2..137f14fe706 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -37,7 +37,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
-use rustc_span::Symbol;
+use rustc_span::{Symbol, DUMMY_SP};
 use rustc_target::abi::FIRST_VARIANT;
 
 use std::cmp;
@@ -467,6 +467,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 ty::ParamEnv::reveal_all(),
                 start_def_id,
                 cx.tcx().mk_args(&[main_ret_ty.into()]),
+                DUMMY_SP,
             );
             let start_fn = cx.get_fn_addr(start_instance);
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index 0577ba32ffd..ac2b6ca4e95 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -281,6 +281,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
                 | TerminatorKind::UnwindResume
                 | TerminatorKind::UnwindTerminate(_)
                 | TerminatorKind::Return
+                | TerminatorKind::TailCall { .. }
                 | TerminatorKind::CoroutineDrop
                 | TerminatorKind::Unreachable
                 | TerminatorKind::SwitchInt { .. }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index b1c22faf1ae..6a5525dc2b3 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -403,7 +403,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             //
             // Why only in unoptimized builds?
             // - In unoptimized builds LLVM uses FastISel which does not support switches, so it
-            //   must fall back to the to the slower SelectionDAG isel. Therefore, using `br` gives
+            //   must fall back to the slower SelectionDAG isel. Therefore, using `br` gives
             //   significant compile time speedups for unoptimized builds.
             // - In optimized builds the above doesn't hold, and using `br` sometimes results in
             //   worse generated code because LLVM can no longer tell that the value being switched
@@ -842,6 +842,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         ty::ParamEnv::reveal_all(),
                         def_id,
                         args,
+                        fn_span,
                     )
                     .polymorphize(bx.tcx()),
                 ),
@@ -1388,6 +1389,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 fn_span,
                 mergeable_succ(),
             ),
+            mir::TerminatorKind::TailCall { .. } => {
+                // FIXME(explicit_tail_calls): implement tail calls in ssa backend
+                span_bug!(
+                    terminator.source_info.span,
+                    "`TailCall` terminator is not yet supported by `rustc_codegen_ssa`"
+                )
+            }
             mir::TerminatorKind::CoroutineDrop | mir::TerminatorKind::Yield { .. } => {
                 bug!("coroutine ops in codegen")
             }
@@ -1521,7 +1529,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 //   when passed by value, making it smaller.
                 // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
                 //   when passed by value, making it larger.
-                let copy_bytes = cmp::min(scratch_size.bytes(), arg.layout.size.bytes());
+                let copy_bytes = cmp::min(cast.unaligned_size(bx).bytes(), arg.layout.size.bytes());
                 // Allocate some scratch space...
                 let llscratch = bx.alloca(scratch_size, scratch_align);
                 bx.lifetime_start(llscratch, scratch_size);
diff --git a/compiler/rustc_codegen_ssa/src/mir/locals.rs b/compiler/rustc_codegen_ssa/src/mir/locals.rs
index a6c873e195e..5190021c005 100644
--- a/compiler/rustc_codegen_ssa/src/mir/locals.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/locals.rs
@@ -47,7 +47,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     let expected_ty = self.monomorphize(self.mir.local_decls[local].ty);
                     if expected_ty != op.layout.ty {
                         warn!(
-                            "Unexpected initial operand type: expected {expected_ty:?}, found {:?}.\
+                            "Unexpected initial operand type:\nexpected {expected_ty:?},\nfound    {:?}.\n\
                             See <https://github.com/rust-lang/rust/issues/114858>.",
                             op.layout.ty
                         );
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index e8da9842882..61f57c9030a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -230,10 +230,20 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             let layout = start_bx.layout_of(fx.monomorphize(decl.ty));
             assert!(!layout.ty.has_erasable_regions());
 
-            if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
-                debug!("alloc: {:?} (return place) -> place", local);
-                let llretptr = start_bx.get_param(0);
-                return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
+            if local == mir::RETURN_PLACE {
+                match fx.fn_abi.ret.mode {
+                    PassMode::Indirect { .. } => {
+                        debug!("alloc: {:?} (return place) -> place", local);
+                        let llretptr = start_bx.get_param(0);
+                        return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
+                    }
+                    PassMode::Cast { ref cast, .. } => {
+                        debug!("alloc: {:?} (return place) -> place", local);
+                        let size = cast.size(&start_bx);
+                        return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout));
+                    }
+                    _ => {}
+                };
             }
 
             if memory_locals.contains(local) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 449fd9ae0db..97d5bb83128 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -109,8 +109,16 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         bx: &mut Bx,
         layout: TyAndLayout<'tcx>,
     ) -> Self {
+        Self::alloca_size(bx, layout.size, layout)
+    }
+
+    pub fn alloca_size<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
+        bx: &mut Bx,
+        size: Size,
+        layout: TyAndLayout<'tcx>,
+    ) -> Self {
         assert!(layout.is_sized(), "tried to statically allocate unsized place");
-        PlaceValue::alloca(bx, layout.size, layout.align.abi).with_type(layout)
+        PlaceValue::alloca(bx, size, layout.align.abi).with_type(layout)
     }
 
     /// Returns a place for an indirect reference to an unsized place.
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index ab60cc37920..523d55fe2d0 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
 use rustc_middle::ty::{Instance, InstanceKind, TypeVisitableExt};
 use rustc_mir_dataflow::Analysis;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
 use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
 
@@ -135,6 +135,8 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
         ccx: &'mir ConstCx<'mir, 'tcx>,
         tainted_by_errors: Option<ErrorGuaranteed>,
     ) -> ConstQualifs {
+        // FIXME(explicit_tail_calls): uhhhh I think we can return without return now, does it change anything
+
         // Find the `Return` terminator if one exists.
         //
         // If no `Return` terminator exists, this MIR is divergent. Just return the conservative
@@ -711,7 +713,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
         self.super_terminator(terminator, location);
 
         match &terminator.kind {
-            TerminatorKind::Call { func, args, fn_span, call_source, .. } => {
+            TerminatorKind::Call { func, args, fn_span, .. }
+            | TerminatorKind::TailCall { func, args, fn_span, .. } => {
+                let call_source = match terminator.kind {
+                    TerminatorKind::Call { call_source, .. } => call_source,
+                    TerminatorKind::TailCall { .. } => CallSource::Normal,
+                    _ => unreachable!(),
+                };
+
                 let ConstCx { tcx, body, param_env, .. } = *self.ccx;
                 let caller = self.def_id();
 
@@ -768,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                         is_trait = true;
 
                         if let Ok(Some(instance)) =
-                            Instance::resolve(tcx, param_env, callee, fn_args)
+                            Instance::try_resolve(tcx, param_env, callee, fn_args)
                             && let InstanceKind::Item(def) = instance.def
                         {
                             // Resolve a trait method call to its concrete implementation, which may be in a
@@ -783,7 +792,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             callee,
                             args: fn_args,
                             span: *fn_span,
-                            call_source: *call_source,
+                            call_source,
                             feature: Some(if tcx.features().const_trait_impl {
                                 sym::effects
                             } else {
@@ -830,7 +839,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                         callee,
                         args: fn_args,
                         span: *fn_span,
-                        call_source: *call_source,
+                        call_source,
                         feature: None,
                     });
                     return;
diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
index f0763f1e490..f5e745454ab 100644
--- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
@@ -108,6 +108,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
 
             mir::TerminatorKind::UnwindTerminate(_)
             | mir::TerminatorKind::Call { .. }
+            | mir::TerminatorKind::TailCall { .. }
             | mir::TerminatorKind::Assert { .. }
             | mir::TerminatorKind::FalseEdge { .. }
             | mir::TerminatorKind::FalseUnwind { .. }
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 99276bac035..17e1d8566c2 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -253,6 +253,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
                 ty::ParamEnv::reveal_all(),
                 const_def_id,
                 instance.args,
+                self.cur_span(),
             );
 
             return Ok(Some(new_instance));
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index b3a139d553a..181c7115386 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -245,7 +245,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // The tag of a `Single` enum is like the tag of the niched
                 // variant: there's no tag as the discriminant is encoded
                 // entirely implicitly. If `write_discriminant` ever hits this
-                // case, we do a "validation read" to ensure the the right
+                // case, we do a "validation read" to ensure the right
                 // discriminant is encoded implicitly, so any attempt to write
                 // the wrong discriminant for a `Single` enum will reliably
                 // result in UB.
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 67eeb1b3b87..6d3e5ea1031 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -26,8 +26,8 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou
 use super::{
     err_inval, throw_inval, throw_ub, throw_ub_custom, throw_unsup, GlobalId, Immediate,
     InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, MemoryKind,
-    OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable, Provenance, Scalar,
-    StackPopJump,
+    OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable, Provenance,
+    ReturnAction, Scalar,
 };
 use crate::errors;
 use crate::util;
@@ -159,6 +159,19 @@ pub enum StackPopCleanup {
     Root { cleanup: bool },
 }
 
+/// Return type of [`InterpCx::pop_stack_frame`].
+pub struct StackPopInfo<'tcx, Prov: Provenance> {
+    /// Additional information about the action to be performed when returning from the popped
+    /// stack frame.
+    pub return_action: ReturnAction,
+
+    /// [`return_to_block`](Frame::return_to_block) of the popped stack frame.
+    pub return_to_block: StackPopCleanup,
+
+    /// [`return_place`](Frame::return_place) of the popped stack frame.
+    pub return_place: MPlaceTy<'tcx, Prov>,
+}
+
 /// State of a local variable including a memoized layout
 #[derive(Clone)]
 pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
@@ -618,7 +631,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         trace!("resolve: {:?}, {:#?}", def, args);
         trace!("param_env: {:#?}", self.param_env);
         trace!("args: {:#?}", args);
-        match ty::Instance::resolve(*self.tcx, self.param_env, def, args) {
+        match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) {
             Ok(Some(instance)) => Ok(instance),
             Ok(None) => throw_inval!(TooGeneric),
 
@@ -803,14 +816,31 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
         trace!("body: {:#?}", body);
+
+        // First push a stack frame so we have access to the local args
+        self.push_new_stack_frame(instance, body, return_to_block, return_place.clone())?;
+
+        self.after_stack_frame_push(instance, body)?;
+
+        Ok(())
+    }
+
+    /// Creates a new stack frame, initializes it and pushes it onto the stack.
+    /// A private helper for [`push_stack_frame`](InterpCx::push_stack_frame).
+    fn push_new_stack_frame(
+        &mut self,
+        instance: ty::Instance<'tcx>,
+        body: &'tcx mir::Body<'tcx>,
+        return_to_block: StackPopCleanup,
+        return_place: MPlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx> {
         let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) };
         let locals = IndexVec::from_elem(dead_local, &body.local_decls);
-        // First push a stack frame so we have access to the local args
         let pre_frame = Frame {
             body,
             loc: Right(body.span), // Span used for errors caused during preamble.
             return_to_block,
-            return_place: return_place.clone(),
+            return_place,
             locals,
             instance,
             tracing_span: SpanGuard::new(),
@@ -819,6 +849,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let frame = M::init_frame(self, pre_frame)?;
         self.stack_mut().push(frame);
 
+        Ok(())
+    }
+
+    /// A private helper for [`push_stack_frame`](InterpCx::push_stack_frame).
+    fn after_stack_frame_push(
+        &mut self,
+        instance: ty::Instance<'tcx>,
+        body: &'tcx mir::Body<'tcx>,
+    ) -> InterpResult<'tcx> {
         // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
         for &const_ in &body.required_consts {
             let c =
@@ -839,6 +878,61 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(())
     }
 
+    /// Pops a stack frame from the stack and returns some information about it.
+    ///
+    /// This also deallocates locals, if necessary.
+    ///
+    /// [`M::before_stack_pop`] should be called before calling this function.
+    /// [`M::after_stack_pop`] is called by this function automatically.
+    ///
+    /// [`M::before_stack_pop`]: Machine::before_stack_pop
+    /// [`M::after_stack_pop`]: Machine::after_stack_pop
+    pub fn pop_stack_frame(
+        &mut self,
+        unwinding: bool,
+    ) -> InterpResult<'tcx, StackPopInfo<'tcx, M::Provenance>> {
+        let cleanup = self.cleanup_current_frame_locals()?;
+
+        let frame =
+            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
+
+        let return_to_block = frame.return_to_block;
+        let return_place = frame.return_place.clone();
+
+        let return_action;
+        if cleanup {
+            return_action = M::after_stack_pop(self, frame, unwinding)?;
+            assert_ne!(return_action, ReturnAction::NoCleanup);
+        } else {
+            return_action = ReturnAction::NoCleanup;
+        };
+
+        Ok(StackPopInfo { return_action, return_to_block, return_place })
+    }
+
+    /// A private helper for [`pop_stack_frame`](InterpCx::pop_stack_frame).
+    /// Returns `true` if cleanup has been done, `false` otherwise.
+    fn cleanup_current_frame_locals(&mut self) -> InterpResult<'tcx, bool> {
+        // Cleanup: deallocate locals.
+        // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
+        // We do this while the frame is still on the stack, so errors point to the callee.
+        let return_to_block = self.frame().return_to_block;
+        let cleanup = match return_to_block {
+            StackPopCleanup::Goto { .. } => true,
+            StackPopCleanup::Root { cleanup, .. } => cleanup,
+        };
+
+        if cleanup {
+            // We need to take the locals out, since we need to mutate while iterating.
+            let locals = mem::take(&mut self.frame_mut().locals);
+            for local in &locals {
+                self.deallocate_local(local.value)?;
+            }
+        }
+
+        Ok(cleanup)
+    }
+
     /// Jump to the given block.
     #[inline]
     pub fn go_to_block(&mut self, target: mir::BasicBlock) {
@@ -886,7 +980,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     }
 
     /// Pops the current frame from the stack, deallocating the
-    /// memory for allocated locals.
+    /// memory for allocated locals, and jumps to an appropriate place.
     ///
     /// If `unwinding` is `false`, then we are performing a normal return
     /// from a function. In this case, we jump back into the frame of the caller,
@@ -899,7 +993,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// The cleanup block ends with a special `Resume` terminator, which will
     /// cause us to continue unwinding.
     #[instrument(skip(self), level = "debug")]
-    pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> {
+    pub(super) fn return_from_current_stack_frame(
+        &mut self,
+        unwinding: bool,
+    ) -> InterpResult<'tcx> {
         info!(
             "popping stack frame ({})",
             if unwinding { "during unwinding" } else { "returning from function" }
@@ -947,45 +1044,31 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             Ok(())
         };
 
-        // Cleanup: deallocate locals.
-        // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
-        // We do this while the frame is still on the stack, so errors point to the callee.
-        let return_to_block = self.frame().return_to_block;
-        let cleanup = match return_to_block {
-            StackPopCleanup::Goto { .. } => true,
-            StackPopCleanup::Root { cleanup, .. } => cleanup,
-        };
-        if cleanup {
-            // We need to take the locals out, since we need to mutate while iterating.
-            let locals = mem::take(&mut self.frame_mut().locals);
-            for local in &locals {
-                self.deallocate_local(local.value)?;
-            }
-        }
-
         // All right, now it is time to actually pop the frame.
-        // Note that its locals are gone already, but that's fine.
-        let frame =
-            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
+        let stack_pop_info = self.pop_stack_frame(unwinding)?;
+
         // Report error from return value copy, if any.
         copy_ret_result?;
 
-        // If we are not doing cleanup, also skip everything else.
-        if !cleanup {
-            assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
-            assert!(!unwinding, "tried to skip cleanup during unwinding");
-            // Skip machine hook.
-            return Ok(());
-        }
-        if M::after_stack_pop(self, frame, unwinding)? == StackPopJump::NoJump {
-            // The hook already did everything.
-            return Ok(());
+        match stack_pop_info.return_action {
+            ReturnAction::Normal => {}
+            ReturnAction::NoJump => {
+                // The hook already did everything.
+                return Ok(());
+            }
+            ReturnAction::NoCleanup => {
+                // If we are not doing cleanup, also skip everything else.
+                assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
+                assert!(!unwinding, "tried to skip cleanup during unwinding");
+                // Skip machine hook.
+                return Ok(());
+            }
         }
 
         // Normal return, figure out where to jump.
         if unwinding {
             // Follow the unwind edge.
-            let unwind = match return_to_block {
+            let unwind = match stack_pop_info.return_to_block {
                 StackPopCleanup::Goto { unwind, .. } => unwind,
                 StackPopCleanup::Root { .. } => {
                     panic!("encountered StackPopCleanup::Root when unwinding!")
@@ -995,7 +1078,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             self.unwind_to_block(unwind)
         } else {
             // Follow the normal return edge.
-            match return_to_block {
+            match stack_pop_info.return_to_block {
                 StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
                 StackPopCleanup::Root { .. } => {
                     assert!(
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 1d54da267ee..d86f1a7a34f 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -301,9 +301,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         }
                         // The signed form of the intrinsic allows this. If we interpret the
                         // difference as isize, we'll get the proper signed difference. If that
-                        // seems *positive*, they were more than isize::MAX apart.
+                        // seems *positive* or equal to isize::MIN, they were more than isize::MAX apart.
                         let dist = val.to_target_isize(self)?;
-                        if dist >= 0 {
+                        if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() {
                             throw_ub_custom!(
                                 fluent::const_eval_offset_from_underflow,
                                 name = intrinsic_name,
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index e91ab7c1791..7f2e9ce06a5 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -23,10 +23,11 @@ use super::{
     MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance,
 };
 
-/// Data returned by Machine::stack_pop,
-/// to provide further control over the popping of the stack frame
+/// Data returned by [`Machine::after_stack_pop`], and consumed by
+/// [`InterpCx::return_from_current_stack_frame`] to determine what actions should be done when
+/// returning from a stack frame.
 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
-pub enum StackPopJump {
+pub enum ReturnAction {
     /// Indicates that no special handling should be
     /// done - we'll either return normally or unwind
     /// based on the terminator for the function
@@ -36,6 +37,9 @@ pub enum StackPopJump {
     /// Indicates that we should *not* jump to the return/unwind address, as the callback already
     /// took care of everything.
     NoJump,
+
+    /// Returned by [`InterpCx::pop_stack_frame`] when no cleanup should be done.
+    NoCleanup,
 }
 
 /// Whether this kind of memory is allowed to leak
@@ -522,10 +526,10 @@ pub trait Machine<'tcx>: Sized {
         _ecx: &mut InterpCx<'tcx, Self>,
         _frame: Frame<'tcx, Self::Provenance, Self::FrameExtra>,
         unwinding: bool,
-    ) -> InterpResult<'tcx, StackPopJump> {
+    ) -> InterpResult<'tcx, ReturnAction> {
         // By default, we do not support unwinding from panics
         assert!(!unwinding);
-        Ok(StackPopJump::Normal)
+        Ok(ReturnAction::Normal)
     }
 
     /// Called immediately after actual memory was allocated for a local
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 9d0c4908225..36fe8dfdd29 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -308,7 +308,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let Some((alloc_kind, mut alloc)) = self.memory.alloc_map.remove(&alloc_id) else {
             // Deallocating global memory -- always an error
             return Err(match self.tcx.try_get_global_alloc(alloc_id) {
-                Some(GlobalAlloc::Function(..)) => {
+                Some(GlobalAlloc::Function { .. }) => {
                     err_ub_custom!(
                         fluent::const_eval_invalid_dealloc,
                         alloc_id = alloc_id,
@@ -555,7 +555,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // Memory of a constant or promoted or anonymous memory referenced by a static.
                 (mem, None)
             }
-            Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)),
+            Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)),
             Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
             None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)),
             Some(GlobalAlloc::Static(def_id)) => {
@@ -828,7 +828,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let alloc = alloc.inner();
                 (alloc.size(), alloc.align, AllocKind::LiveData)
             }
-            Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
+            Some(GlobalAlloc::Function { .. }) => {
+                bug!("We already checked function pointers above")
+            }
             Some(GlobalAlloc::VTable(..)) => {
                 // No data to be accessed here. But vtables are pointer-aligned.
                 return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable);
@@ -865,7 +867,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             Some(FnVal::Other(*extra))
         } else {
             match self.tcx.try_get_global_alloc(id) {
-                Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)),
+                Some(GlobalAlloc::Function { instance, .. }) => Some(FnVal::Instance(instance)),
                 _ => None,
             }
         }
@@ -1056,8 +1058,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> {
                                 alloc.inner(),
                             )?;
                         }
-                        Some(GlobalAlloc::Function(func)) => {
-                            write!(fmt, " (fn: {func})")?;
+                        Some(GlobalAlloc::Function { instance, .. }) => {
+                            write!(fmt, " (fn: {instance})")?;
                         }
                         Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => {
                             write!(fmt, " (vtable: impl {trait_ref} for {ty})")?;
diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs
index 7d7b421f869..f703c6fbe3e 100644
--- a/compiler/rustc_const_eval/src/interpret/mod.rs
+++ b/compiler/rustc_const_eval/src/interpret/mod.rs
@@ -26,7 +26,7 @@ pub use self::intern::{
     intern_const_alloc_for_constprop, intern_const_alloc_recursive, HasStaticRootDefId, InternKind,
     InternResult,
 };
-pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
+pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, ReturnAction};
 pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
 pub use self::operand::{ImmTy, Immediate, OpTy, Readable};
 pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 1baf62baa81..b3124dfdfbc 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -32,7 +32,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // We are unwinding and this fn has no cleanup code.
             // Just go on unwinding.
             trace!("unwinding: skipping frame");
-            self.pop_stack_frame(/* unwinding */ true)?;
+            self.return_from_current_stack_frame(/* unwinding */ true)?;
             return Ok(true);
         };
         let basic_block = &self.body().basic_blocks[loc.block];
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 74521d0f493..25f6bd64055 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -4,9 +4,8 @@ use either::Either;
 use rustc_middle::ty::TyCtxt;
 use tracing::trace;
 
-use rustc_middle::span_bug;
 use rustc_middle::{
-    mir,
+    bug, mir, span_bug,
     ty::{
         self,
         layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout},
@@ -26,7 +25,10 @@ use super::{
     InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, Provenance, Scalar,
     StackPopCleanup,
 };
-use crate::fluent_generated as fluent;
+use crate::{
+    fluent_generated as fluent,
+    interpret::{eval_context::StackPopInfo, ReturnAction},
+};
 
 /// An argment passed to a function.
 #[derive(Clone, Debug)]
@@ -47,6 +49,15 @@ impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
     }
 }
 
+struct EvaluatedCalleeAndArgs<'tcx, M: Machine<'tcx>> {
+    callee: FnVal<'tcx, M::ExtraFnVal>,
+    args: Vec<FnArg<'tcx, M::Provenance>>,
+    fn_sig: ty::FnSig<'tcx>,
+    fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
+    /// True if the function is marked as `#[track_caller]` ([`ty::InstanceKind::requires_caller_location`])
+    with_caller_location: bool,
+}
+
 impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
     /// original memory occurs.
@@ -84,7 +95,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         use rustc_middle::mir::TerminatorKind::*;
         match terminator.kind {
             Return => {
-                self.pop_stack_frame(/* unwinding */ false)?
+                self.return_from_current_stack_frame(/* unwinding */ false)?
             }
 
             Goto { target } => self.go_to_block(target),
@@ -124,40 +135,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             } => {
                 let old_stack = self.frame_idx();
                 let old_loc = self.frame().loc;
-                let func = self.eval_operand(func, None)?;
-                let args = self.eval_fn_call_arguments(args)?;
-
-                let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
-                let fn_sig =
-                    self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
-                let extra_args = &args[fn_sig.inputs().len()..];
-                let extra_args =
-                    self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));
-
-                let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
-                    ty::FnPtr(_sig) => {
-                        let fn_ptr = self.read_pointer(&func)?;
-                        let fn_val = self.get_ptr_fn(fn_ptr)?;
-                        (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false)
-                    }
-                    ty::FnDef(def_id, args) => {
-                        let instance = self.resolve(def_id, args)?;
-                        (
-                            FnVal::Instance(instance),
-                            self.fn_abi_of_instance(instance, extra_args)?,
-                            instance.def.requires_caller_location(*self.tcx),
-                        )
-                    }
-                    _ => span_bug!(
-                        terminator.source_info.span,
-                        "invalid callee of type {}",
-                        func.layout.ty
-                    ),
-                };
+
+                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
+                    self.eval_callee_and_args(terminator, func, args)?;
 
                 let destination = self.force_allocation(&self.eval_place(destination)?)?;
                 self.eval_fn_call(
-                    fn_val,
+                    callee,
                     (fn_sig.abi, fn_abi),
                     &args,
                     with_caller_location,
@@ -172,6 +156,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 }
             }
 
+            TailCall { ref func, ref args, fn_span: _ } => {
+                let old_frame_idx = self.frame_idx();
+
+                let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
+                    self.eval_callee_and_args(terminator, func, args)?;
+
+                self.eval_fn_tail_call(callee, (fn_sig.abi, fn_abi), &args, with_caller_location)?;
+
+                if self.frame_idx() != old_frame_idx {
+                    span_bug!(
+                        terminator.source_info.span,
+                        "evaluating this tail call pushed a new stack frame"
+                    );
+                }
+            }
+
             Drop { place, target, unwind, replace: _ } => {
                 let place = self.eval_place(place)?;
                 let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
@@ -209,7 +209,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 trace!("unwinding: resuming from cleanup");
                 // By definition, a Resume terminator means
                 // that we're unwinding
-                self.pop_stack_frame(/* unwinding */ true)?;
+                self.return_from_current_stack_frame(/* unwinding */ true)?;
                 return Ok(());
             }
 
@@ -514,6 +514,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         Ok(())
     }
 
+    /// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the
+    /// necessary information about callee and arguments to make a call.
+    fn eval_callee_and_args(
+        &self,
+        terminator: &mir::Terminator<'tcx>,
+        func: &mir::Operand<'tcx>,
+        args: &[Spanned<mir::Operand<'tcx>>],
+    ) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
+        let func = self.eval_operand(func, None)?;
+        let args = self.eval_fn_call_arguments(args)?;
+
+        let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
+        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
+        let extra_args = &args[fn_sig.inputs().len()..];
+        let extra_args =
+            self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));
+
+        let (callee, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
+            ty::FnPtr(_sig) => {
+                let fn_ptr = self.read_pointer(&func)?;
+                let fn_val = self.get_ptr_fn(fn_ptr)?;
+                (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false)
+            }
+            ty::FnDef(def_id, args) => {
+                let instance = self.resolve(def_id, args)?;
+                (
+                    FnVal::Instance(instance),
+                    self.fn_abi_of_instance(instance, extra_args)?,
+                    instance.def.requires_caller_location(*self.tcx),
+                )
+            }
+            _ => {
+                span_bug!(terminator.source_info.span, "invalid callee of type {}", func.layout.ty)
+            }
+        };
+
+        Ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location })
+    }
+
     /// Call this function -- pushing the stack frame and initializing the arguments.
     ///
     /// `caller_fn_abi` is used to determine if all the arguments are passed the proper way.
@@ -883,13 +922,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         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::resolve_for_vtable(
+                    let concrete_method = Instance::expect_resolve_for_vtable(
                         tcx,
                         self.param_env,
                         def_id,
                         instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
-                    )
-                    .unwrap();
+                        self.cur_span(),
+                    );
                     assert_eq!(fn_inst, concrete_method);
                 }
 
@@ -924,6 +963,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
     }
 
+    pub(crate) fn eval_fn_tail_call(
+        &mut self,
+        fn_val: FnVal<'tcx, M::ExtraFnVal>,
+        (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
+        args: &[FnArg<'tcx, M::Provenance>],
+        with_caller_location: bool,
+    ) -> InterpResult<'tcx> {
+        trace!("eval_fn_call: {:#?}", fn_val);
+
+        // This is the "canonical" implementation of tails calls,
+        // a pop of the current stack frame, followed by a normal call
+        // which pushes a new stack frame, with the return address from
+        // the popped stack frame.
+        //
+        // Note that we are using `pop_stack_frame` and not `return_from_current_stack_frame`,
+        // as the latter "executes" the goto to the return block, but we don't want to,
+        // only the tail called function should return to the current return block.
+        M::before_stack_pop(self, self.frame())?;
+
+        let StackPopInfo { return_action, return_to_block, return_place } =
+            self.pop_stack_frame(false)?;
+
+        assert_eq!(return_action, ReturnAction::Normal);
+
+        let StackPopCleanup::Goto { ret, unwind } = return_to_block else {
+            bug!("can't tailcall as root");
+        };
+
+        // FIXME(explicit_tail_calls):
+        //   we should check if both caller&callee can/n't unwind,
+        //   see <https://github.com/rust-lang/rust/pull/113128#issuecomment-1614979803>
+
+        self.eval_fn_call(
+            fn_val,
+            (caller_abi, caller_fn_abi),
+            args,
+            with_caller_location,
+            &return_place,
+            ret,
+            unwind,
+        )
+    }
+
     fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> {
         // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
         let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index add48e1b186..7fea0617666 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -745,7 +745,7 @@ fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId)
             }
         }
         GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
-        GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => {
+        GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => {
             // These are immutable, we better don't allow mutable pointers here.
             Mutability::Not
         }
diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs
index fed23df10dc..812ed410a94 100644
--- a/compiler/rustc_data_structures/src/sip128.rs
+++ b/compiler/rustc_data_structures/src/sip128.rs
@@ -70,18 +70,19 @@ macro_rules! compress {
     ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }};
     ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{
         $v0 = $v0.wrapping_add($v1);
+        $v2 = $v2.wrapping_add($v3);
         $v1 = $v1.rotate_left(13);
         $v1 ^= $v0;
-        $v0 = $v0.rotate_left(32);
-        $v2 = $v2.wrapping_add($v3);
         $v3 = $v3.rotate_left(16);
         $v3 ^= $v2;
-        $v0 = $v0.wrapping_add($v3);
-        $v3 = $v3.rotate_left(21);
-        $v3 ^= $v0;
+        $v0 = $v0.rotate_left(32);
+
         $v2 = $v2.wrapping_add($v1);
+        $v0 = $v0.wrapping_add($v3);
         $v1 = $v1.rotate_left(17);
         $v1 ^= $v2;
+        $v3 = $v3.rotate_left(21);
+        $v3 ^= $v0;
         $v2 = $v2.rotate_left(32);
     }};
 }
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 79ceb28abb5..058a675c40d 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -35,11 +35,11 @@
 //! |                         |                     |                                 |
 //! | `ParallelIterator`      | `Iterator`          | `rayon::iter::ParallelIterator` |
 //!
-//! [^1] `MTLock` is similar to `Lock`, but the serial version avoids the cost
+//! [^1]: `MTLock` is similar to `Lock`, but the serial version avoids the cost
 //! of a `RefCell`. This is appropriate when interior mutability is not
 //! required.
 //!
-//! [^2] `MTRef`, `MTLockRef` are type aliases.
+//! [^2]: `MTRef`, `MTLockRef` are type aliases.
 
 pub use crate::marker::*;
 use std::collections::HashMap;
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index bbe9741bf44..ad2acb03b3f 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -30,7 +30,7 @@ use rustc_errors::{
 };
 use rustc_feature::find_gated_cfg;
 use rustc_interface::util::{self, get_codegen_backend};
-use rustc_interface::{interface, passes, Queries};
+use rustc_interface::{interface, passes, Linker, Queries};
 use rustc_lint::unerased_lint_store;
 use rustc_metadata::creader::MetadataLoader;
 use rustc_metadata::locator;
@@ -41,7 +41,6 @@ use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
 use rustc_session::output::collect_crate_types;
 use rustc_session::{config, filesearch, EarlyDiagCtxt, Session};
-use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::source_map::FileLoader;
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
@@ -448,21 +447,9 @@ fn run_compiler(
                 return early_exit();
             }
 
-            let linker = queries.codegen_and_build_linker()?;
-
-            // This must run after monomorphization so that all generic types
-            // have been instantiated.
-            if sess.opts.unstable_opts.print_type_sizes {
-                sess.code_stats.print_type_sizes();
-            }
-
-            if sess.opts.unstable_opts.print_vtable_sizes {
-                let crate_name = queries.global_ctxt()?.enter(|tcx| tcx.crate_name(LOCAL_CRATE));
-
-                sess.code_stats.print_vtable_sizes(crate_name);
-            }
-
-            Ok(Some(linker))
+            queries.global_ctxt()?.enter(|tcx| {
+                Ok(Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)?))
+            })
         })?;
 
         // Linking is done outside the `compiler.enter()` so that the
diff --git a/compiler/rustc_error_codes/src/error_codes/E0502.md b/compiler/rustc_error_codes/src/error_codes/E0502.md
index dc3ffdfddd9..85f38b9286f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0502.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0502.md
@@ -1,4 +1,5 @@
-A variable already borrowed as immutable was borrowed as mutable.
+A variable already borrowed with a certain mutability (either mutable or
+immutable) was borrowed again with a different mutability.
 
 Erroneous code example:
 
@@ -13,7 +14,7 @@ fn foo(a: &mut i32) {
 ```
 
 To fix this error, ensure that you don't have any other references to the
-variable before trying to access it mutably:
+variable before trying to access it with a different mutability:
 
 ```
 fn bar(x: &mut i32) {}
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 0af80bc5c67..e6ca1bf7bc4 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -298,15 +298,21 @@ impl IntoDiagArg for hir::def::Namespace {
 }
 
 #[derive(Clone)]
-pub struct DiagSymbolList(Vec<Symbol>);
+pub struct DiagSymbolList<S = Symbol>(Vec<S>);
 
-impl From<Vec<Symbol>> for DiagSymbolList {
-    fn from(v: Vec<Symbol>) -> Self {
+impl<S> From<Vec<S>> for DiagSymbolList<S> {
+    fn from(v: Vec<S>) -> Self {
         DiagSymbolList(v)
     }
 }
 
-impl IntoDiagArg for DiagSymbolList {
+impl<S> FromIterator<S> for DiagSymbolList<S> {
+    fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Self {
+        iter.into_iter().collect::<Vec<_>>().into()
+    }
+}
+
+impl<S: std::fmt::Display> IntoDiagArg for DiagSymbolList<S> {
     fn into_diag_arg(self) -> DiagArgValue {
         DiagArgValue::StrListSepByAnd(
             self.0.into_iter().map(|sym| Cow::Owned(format!("`{sym}`"))).collect(),
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 45118bcc58a..aa47ca16676 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -2273,9 +2273,26 @@ impl HumanEmitter {
                     &normalize_whitespace(last_line),
                     Style::NoStyle,
                 );
-                buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
-                buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
-                buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
+                if !line_to_add.trim().is_empty() {
+                    // Check if after the removal, the line is left with only whitespace. If so, we
+                    // will not show an "addition" line, as removing the whole line is what the user
+                    // would really want.
+                    // For example, for the following:
+                    //   |
+                    // 2 -     .await
+                    // 2 +     (note the left over whitepsace)
+                    //   |
+                    // We really want
+                    //   |
+                    // 2 -     .await
+                    //   |
+                    // *row_num -= 1;
+                    buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+                    buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+                    buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
+                } else {
+                    *row_num -= 1;
+                }
             } else {
                 *row_num -= 2;
             }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 56cbb54fcec..40e16b45115 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -172,7 +172,7 @@ impl<'a> StripUnconfigured<'a> {
     fn configure_tokens(&self, stream: &AttrTokenStream) -> AttrTokenStream {
         fn can_skip(stream: &AttrTokenStream) -> bool {
             stream.0.iter().all(|tree| match tree {
-                AttrTokenTree::Attributes(_) => false,
+                AttrTokenTree::AttrsTarget(_) => false,
                 AttrTokenTree::Token(..) => true,
                 AttrTokenTree::Delimited(.., inner) => can_skip(inner),
             })
@@ -185,22 +185,22 @@ impl<'a> StripUnconfigured<'a> {
         let trees: Vec<_> = stream
             .0
             .iter()
-            .flat_map(|tree| match tree.clone() {
-                AttrTokenTree::Attributes(mut data) => {
-                    data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
+            .filter_map(|tree| match tree.clone() {
+                AttrTokenTree::AttrsTarget(mut target) => {
+                    target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
 
-                    if self.in_cfg(&data.attrs) {
-                        data.tokens = LazyAttrTokenStream::new(
-                            self.configure_tokens(&data.tokens.to_attr_token_stream()),
+                    if self.in_cfg(&target.attrs) {
+                        target.tokens = LazyAttrTokenStream::new(
+                            self.configure_tokens(&target.tokens.to_attr_token_stream()),
                         );
-                        Some(AttrTokenTree::Attributes(data)).into_iter()
+                        Some(AttrTokenTree::AttrsTarget(target))
                     } else {
-                        None.into_iter()
+                        None
                     }
                 }
                 AttrTokenTree::Delimited(sp, spacing, delim, mut inner) => {
                     inner = self.configure_tokens(&inner);
-                    Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter()
+                    Some(AttrTokenTree::Delimited(sp, spacing, delim, inner))
                 }
                 AttrTokenTree::Token(
                     Token {
@@ -220,9 +220,7 @@ impl<'a> StripUnconfigured<'a> {
                 ) => {
                     panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree);
                 }
-                AttrTokenTree::Token(token, spacing) => {
-                    Some(AttrTokenTree::Token(token, spacing)).into_iter()
-                }
+                AttrTokenTree::Token(token, spacing) => Some(AttrTokenTree::Token(token, spacing)),
             })
             .collect();
         AttrTokenStream::new(trees)
@@ -294,7 +292,7 @@ impl<'a> StripUnconfigured<'a> {
         attr: &Attribute,
         (item, item_span): (ast::AttrItem, Span),
     ) -> Attribute {
-        let orig_tokens = attr.tokens();
+        let orig_tokens = attr.get_tokens();
 
         // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
         // and producing an attribute of the form `#[attr]`. We
@@ -310,12 +308,11 @@ impl<'a> StripUnconfigured<'a> {
         else {
             panic!("Bad tokens for attribute {attr:?}");
         };
-        let pound_span = pound_token.span;
 
         // We don't really have a good span to use for the synthesized `[]`
         // in `#[attr]`, so just use the span of the `#` token.
         let bracket_group = AttrTokenTree::Delimited(
-            DelimSpan::from_single(pound_span),
+            DelimSpan::from_single(pound_token.span),
             DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
             Delimiter::Bracket,
             item.tokens
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index bf475c1dc96..2df8b8f00f8 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -120,21 +120,21 @@ struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
 
 struct BestFailure {
     token: Token,
-    position_in_tokenstream: usize,
+    position_in_tokenstream: u32,
     msg: &'static str,
     remaining_matcher: MatcherLoc,
 }
 
 impl BestFailure {
-    fn is_better_position(&self, position: usize) -> bool {
+    fn is_better_position(&self, position: u32) -> bool {
         position > self.position_in_tokenstream
     }
 }
 
 impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> {
-    type Failure = (Token, usize, &'static str);
+    type Failure = (Token, u32, &'static str);
 
-    fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure {
+    fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure {
         (tok, position, msg)
     }
 
@@ -211,9 +211,9 @@ impl<'matcher> FailureForwarder<'matcher> {
 }
 
 impl<'matcher> Tracker<'matcher> for FailureForwarder<'matcher> {
-    type Failure = (Token, usize, &'static str);
+    type Failure = (Token, u32, &'static str);
 
-    fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure {
+    fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure {
         (tok, position, msg)
     }
 
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 2fbd09fd9ae..99a9d4f8912 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -452,7 +452,7 @@ impl TtParser {
         &mut self,
         matcher: &'matcher [MatcherLoc],
         token: &Token,
-        approx_position: usize,
+        approx_position: u32,
         track: &mut T,
     ) -> Option<NamedParseResult<T::Failure>> {
         // Matcher positions that would be valid if the macro invocation was over now. Only
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index e43ba7c3a5a..88ec3d83664 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -153,7 +153,7 @@ pub(super) trait Tracker<'matcher> {
     /// Arm failed to match. If the token is `token::Eof`, it indicates an unexpected
     /// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
     /// The usize is the approximate position of the token in the input token stream.
-    fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure;
+    fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure;
 
     /// This is called before trying to match next MatcherLoc on the current token.
     fn before_match_loc(&mut self, _parser: &TtParser, _matcher: &'matcher MatcherLoc) {}
@@ -182,7 +182,7 @@ pub(super) struct NoopTracker;
 impl<'matcher> Tracker<'matcher> for NoopTracker {
     type Failure = ();
 
-    fn build_failure(_tok: Token, _position: usize, _msg: &'static str) -> Self::Failure {}
+    fn build_failure(_tok: Token, _position: u32, _msg: &'static str) -> Self::Failure {}
 
     fn description() -> &'static str {
         "none"
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index 25958e03028..dbbd948fd70 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -1,4 +1,4 @@
-use rustc_ast::token::{self, Delimiter, IdentIsRaw};
+use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, Token, TokenKind};
 use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree};
 use rustc_ast::{LitIntType, LitKind};
 use rustc_ast_pretty::pprust;
@@ -6,9 +6,10 @@ use rustc_errors::{Applicability, PResult};
 use rustc_macros::{Decodable, Encodable};
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Ident;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 
 pub(crate) const RAW_IDENT_ERR: &str = "`${concat(..)}` currently does not support raw identifiers";
+pub(crate) const UNSUPPORTED_CONCAT_ELEM_ERR: &str = "expected identifier or string literal";
 
 /// A meta-variable expression, for expansions based on properties of meta-variables.
 #[derive(Debug, PartialEq, Encodable, Decodable)]
@@ -51,11 +52,26 @@ impl MetaVarExpr {
                 let mut result = Vec::new();
                 loop {
                     let is_var = try_eat_dollar(&mut iter);
-                    let element_ident = parse_ident(&mut iter, psess, outer_span)?;
+                    let token = parse_token(&mut iter, psess, outer_span)?;
                     let element = if is_var {
-                        MetaVarExprConcatElem::Var(element_ident)
+                        MetaVarExprConcatElem::Var(parse_ident_from_token(psess, token)?)
+                    } else if let TokenKind::Literal(Lit {
+                        kind: token::LitKind::Str,
+                        symbol,
+                        suffix: None,
+                    }) = token.kind
+                    {
+                        MetaVarExprConcatElem::Literal(symbol)
                     } else {
-                        MetaVarExprConcatElem::Ident(element_ident)
+                        match parse_ident_from_token(psess, token) {
+                            Err(err) => {
+                                err.cancel();
+                                return Err(psess
+                                    .dcx()
+                                    .struct_span_err(token.span, UNSUPPORTED_CONCAT_ELEM_ERR));
+                            }
+                            Ok(elem) => MetaVarExprConcatElem::Ident(elem),
+                        }
                     };
                     result.push(element);
                     if iter.look_ahead(0).is_none() {
@@ -105,11 +121,13 @@ impl MetaVarExpr {
 
 #[derive(Debug, Decodable, Encodable, PartialEq)]
 pub(crate) enum MetaVarExprConcatElem {
-    /// There is NO preceding dollar sign, which means that this identifier should be interpreted
-    /// as a literal.
+    /// Identifier WITHOUT a preceding dollar sign, which means that this identifier should be
+    /// interpreted as a literal.
     Ident(Ident),
-    /// There is a preceding dollar sign, which means that this identifier should be expanded
-    /// and interpreted as a variable.
+    /// For example, a number or a string.
+    Literal(Symbol),
+    /// Identifier WITH a preceding dollar sign, which means that this identifier should be
+    /// expanded and interpreted as a variable.
     Var(Ident),
 }
 
@@ -158,7 +176,7 @@ fn parse_depth<'psess>(
     span: Span,
 ) -> PResult<'psess, usize> {
     let Some(tt) = iter.next() else { return Ok(0) };
-    let TokenTree::Token(token::Token { kind: token::TokenKind::Literal(lit), .. }, _) = tt else {
+    let TokenTree::Token(Token { kind: TokenKind::Literal(lit), .. }, _) = tt else {
         return Err(psess
             .dcx()
             .struct_span_err(span, "meta-variable expression depth must be a literal"));
@@ -180,12 +198,14 @@ fn parse_ident<'psess>(
     psess: &'psess ParseSess,
     fallback_span: Span,
 ) -> PResult<'psess, Ident> {
-    let Some(tt) = iter.next() else {
-        return Err(psess.dcx().struct_span_err(fallback_span, "expected identifier"));
-    };
-    let TokenTree::Token(token, _) = tt else {
-        return Err(psess.dcx().struct_span_err(tt.span(), "expected identifier"));
-    };
+    let token = parse_token(iter, psess, fallback_span)?;
+    parse_ident_from_token(psess, token)
+}
+
+fn parse_ident_from_token<'psess>(
+    psess: &'psess ParseSess,
+    token: &Token,
+) -> PResult<'psess, Ident> {
     if let Some((elem, is_raw)) = token.ident() {
         if let IdentIsRaw::Yes = is_raw {
             return Err(psess.dcx().struct_span_err(elem.span, RAW_IDENT_ERR));
@@ -205,10 +225,24 @@ fn parse_ident<'psess>(
     Err(err)
 }
 
+fn parse_token<'psess, 't>(
+    iter: &mut RefTokenTreeCursor<'t>,
+    psess: &'psess ParseSess,
+    fallback_span: Span,
+) -> PResult<'psess, &'t Token> {
+    let Some(tt) = iter.next() else {
+        return Err(psess.dcx().struct_span_err(fallback_span, UNSUPPORTED_CONCAT_ELEM_ERR));
+    };
+    let TokenTree::Token(token, _) = tt else {
+        return Err(psess.dcx().struct_span_err(tt.span(), UNSUPPORTED_CONCAT_ELEM_ERR));
+    };
+    Ok(token)
+}
+
 /// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
 /// iterator is not modified and the result is `false`.
 fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
-    if let Some(TokenTree::Token(token::Token { kind: token::Comma, .. }, _)) = iter.look_ahead(0) {
+    if let Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) = iter.look_ahead(0) {
         let _ = iter.next();
         return true;
     }
@@ -218,8 +252,7 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
 /// Tries to move the iterator forward returning `true` if there is a dollar sign. If not, then the
 /// iterator is not modified and the result is `false`.
 fn try_eat_dollar(iter: &mut RefTokenTreeCursor<'_>) -> bool {
-    if let Some(TokenTree::Token(token::Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0)
-    {
+    if let Some(TokenTree::Token(Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) {
         let _ = iter.next();
         return true;
     }
@@ -232,8 +265,7 @@ fn eat_dollar<'psess>(
     psess: &'psess ParseSess,
     span: Span,
 ) -> PResult<'psess, ()> {
-    if let Some(TokenTree::Token(token::Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0)
-    {
+    if let Some(TokenTree::Token(Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) {
         let _ = iter.next();
         return Ok(());
     }
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index f935f1b77e0..9b4dc13c703 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -11,11 +11,13 @@ use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult};
+use rustc_parse::lexer::nfc_normalize;
 use rustc_parse::parser::ParseNtResult;
 use rustc_session::parse::ParseSess;
+use rustc_session::parse::SymbolGallery;
 use rustc_span::hygiene::{LocalExpnId, Transparency};
 use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
-use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext};
+use rustc_span::{with_metavar_spans, Span, SyntaxContext};
 use smallvec::{smallvec, SmallVec};
 use std::mem;
 
@@ -312,7 +314,16 @@ pub(super) fn transcribe<'a>(
 
             // Replace meta-variable expressions with the result of their expansion.
             mbe::TokenTree::MetaVarExpr(sp, expr) => {
-                transcribe_metavar_expr(dcx, expr, interp, &mut marker, &repeats, &mut result, sp)?;
+                transcribe_metavar_expr(
+                    dcx,
+                    expr,
+                    interp,
+                    &mut marker,
+                    &repeats,
+                    &mut result,
+                    sp,
+                    &psess.symbol_gallery,
+                )?;
             }
 
             // If we are entering a new delimiter, we push its contents to the `stack` to be
@@ -669,6 +680,7 @@ fn transcribe_metavar_expr<'a>(
     repeats: &[(usize, usize)],
     result: &mut Vec<TokenTree>,
     sp: &DelimSpan,
+    symbol_gallery: &SymbolGallery,
 ) -> PResult<'a, ()> {
     let mut visited_span = || {
         let mut span = sp.entire();
@@ -680,16 +692,26 @@ fn transcribe_metavar_expr<'a>(
             let mut concatenated = String::new();
             for element in elements.into_iter() {
                 let string = match element {
-                    MetaVarExprConcatElem::Ident(ident) => ident.to_string(),
-                    MetaVarExprConcatElem::Var(ident) => extract_ident(dcx, *ident, interp)?,
+                    MetaVarExprConcatElem::Ident(elem) => elem.to_string(),
+                    MetaVarExprConcatElem::Literal(elem) => elem.as_str().into(),
+                    MetaVarExprConcatElem::Var(elem) => extract_ident(dcx, *elem, interp)?,
                 };
                 concatenated.push_str(&string);
             }
+            let symbol = nfc_normalize(&concatenated);
+            let concatenated_span = visited_span();
+            if !rustc_lexer::is_ident(symbol.as_str()) {
+                return Err(dcx.struct_span_err(
+                    concatenated_span,
+                    "`${concat(..)}` is not generating a valid identifier",
+                ));
+            }
+            symbol_gallery.insert(symbol, concatenated_span);
             // The current implementation marks the span as coming from the macro regardless of
             // contexts of the concatenated identifiers but this behavior may change in the
             // future.
             result.push(TokenTree::Token(
-                Token::from_ast_ident(Ident::new(Symbol::intern(&concatenated), visited_span())),
+                Token::from_ast_ident(Ident::new(symbol, concatenated_span)),
                 Spacing::Alone,
             ));
         }
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 910402d5499..7b27049a579 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -556,7 +556,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     // RFC 2632
     gated!(
-        const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, const_trait_impl,
+        const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl,
         "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \
         `impls` and all default bodies as `const`, which may be removed or renamed in the \
         future."
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index ad6f7da8937..c05cac155b7 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -575,6 +575,8 @@ declare_features! (
     (unstable, raw_ref_op, "1.41.0", Some(64490)),
     /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
     (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)),
+    /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant
+    (incomplete, ref_pat_eat_one_layer_2024_structural, "CURRENT_RUSTC_VERSION", Some(123076)),
     /// Allows using the `#[register_tool]` attribute.
     (unstable, register_tool, "1.41.0", Some(66079)),
     /// Allows the `#[repr(i128)]` attribute for enums.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 6cccdec94c0..d57fad6ba4c 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2414,7 +2414,7 @@ pub enum ImplItemKind<'hir> {
 /// * the `A: Bound` in `Trait<A: Bound>`
 /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
 /// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
-/// * the `f(): Bound` in `Trait<f(): Bound>` (feature `return_type_notation`)
+/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct AssocItemConstraint<'hir> {
     pub hir_id: HirId,
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 3c44acb1657..30c0e40206a 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -11,6 +11,7 @@ use crate::def_id::DefId;
 use crate::{MethodKind, Target};
 
 use rustc_ast as ast;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -23,6 +24,7 @@ pub struct LanguageItems {
     /// Mappings from lang items to their possibly found [`DefId`]s.
     /// The index corresponds to the order in [`LangItem`].
     items: [Option<DefId>; std::mem::variant_count::<LangItem>()],
+    reverse_items: FxIndexMap<DefId, LangItem>,
     /// Lang items that were not found during collection.
     pub missing: Vec<LangItem>,
 }
@@ -30,7 +32,11 @@ pub struct LanguageItems {
 impl LanguageItems {
     /// Construct an empty collection of lang items and no missing ones.
     pub fn new() -> Self {
-        Self { items: [None; std::mem::variant_count::<LangItem>()], missing: Vec::new() }
+        Self {
+            items: [None; std::mem::variant_count::<LangItem>()],
+            reverse_items: FxIndexMap::default(),
+            missing: Vec::new(),
+        }
     }
 
     pub fn get(&self, item: LangItem) -> Option<DefId> {
@@ -39,6 +45,11 @@ impl LanguageItems {
 
     pub fn set(&mut self, item: LangItem, def_id: DefId) {
         self.items[item as usize] = Some(def_id);
+        self.reverse_items.insert(def_id, item);
+    }
+
+    pub fn from_def_id(&self, def_id: DefId) -> Option<LangItem> {
+        self.reverse_items.get(&def_id).copied()
     }
 
     pub fn iter(&self) -> impl Iterator<Item = (LangItem, DefId)> + '_ {
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 064d9c077b0..24c5377a3b1 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -55,8 +55,6 @@ hir_analysis_cannot_capture_late_bound_ty =
     cannot capture late-bound type parameter in {$what}
     .label = parameter defined here
 
-hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
-
 hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
     .label = `for<...>` is here
 
@@ -375,10 +373,6 @@ hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a t
 hir_analysis_parenthesized_fn_trait_expansion =
     parenthesized trait syntax expands to `{$expanded_type}`
 
-hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
-    .suggestion = cast the value to `{$cast_ty}`
-    .help = cast the value to `{$cast_ty}`
-
 hir_analysis_pattern_type_non_const_range = range patterns must have constant range start and end
 hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pattern types
     .label = this type is the same as the inner type without a pattern
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index c7ee89e73c2..c30a6f1eeb9 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -7,7 +7,7 @@ use rustc_hir::LangItem;
 use rustc_middle::ty::fold::FnMutDelegate;
 use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_span::def_id::DefId;
-use rustc_span::{sym, Span};
+use rustc_span::Span;
 
 /// Collects together a list of type bounds. These lists of bounds occur in many places
 /// in Rust's syntax:
@@ -80,7 +80,7 @@ impl<'tcx> Bounds<'tcx> {
             }
 
             (_, ty::BoundConstness::NotConst) => {
-                if !tcx.has_attr(bound_trait_ref.def_id(), sym::const_trait) {
+                if !tcx.is_const_trait(bound_trait_ref.def_id()) {
                     return;
                 }
                 tcx.consts.true_
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index f93777eda52..bf8ef18c04f 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -25,9 +25,9 @@ use rustc_middle::ty::{
 };
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_target::abi::FieldIdx;
+use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_type_ir::fold::TypeFoldable;
 
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 b5b68471b9d..6c53625b590 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -21,8 +21,9 @@ use rustc_middle::ty::{
 use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
@@ -981,7 +982,7 @@ fn report_trait_method_mismatch<'tcx>(
                 .next()
                 .unwrap_or(impl_err_span);
 
-            diag.span_suggestion(
+            diag.span_suggestion_verbose(
                 span,
                 "change the self-receiver type to match the trait",
                 sugg,
@@ -1005,12 +1006,12 @@ fn report_trait_method_mismatch<'tcx>(
                         }
                         hir::FnRetTy::Return(hir_ty) => {
                             let sugg = trait_sig.output();
-                            diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+                            diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap);
                         }
                     };
                 };
             } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
-                diag.span_suggestion(
+                diag.span_suggestion_verbose(
                     impl_err_span,
                     "change the parameter type to match the trait",
                     trait_ty,
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index cc52a765802..ce921f64481 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -7,7 +7,7 @@ use rustc_session::config::EntryFnType;
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_span::{symbol::sym, Span};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use std::ops::Not;
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index f21aeb4c0b9..6282499883b 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -26,15 +26,12 @@ fn equate_intrinsic_type<'tcx>(
     n_cts: usize,
     sig: ty::PolyFnSig<'tcx>,
 ) {
-    let (own_counts, span) = match tcx.hir_node_by_def_id(def_id) {
+    let (generics, span) = match tcx.hir_node_by_def_id(def_id) {
         hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })
         | hir::Node::ForeignItem(hir::ForeignItem {
             kind: hir::ForeignItemKind::Fn(.., generics, _),
             ..
-        }) => {
-            let own_counts = tcx.generics_of(def_id).own_counts();
-            (own_counts, generics.span)
-        }
+        }) => (tcx.generics_of(def_id), generics.span),
         _ => {
             struct_span_code_err!(tcx.dcx(), span, E0622, "intrinsic must be a function")
                 .with_span_label(span, "expected a function")
@@ -42,6 +39,7 @@ fn equate_intrinsic_type<'tcx>(
             return;
         }
     };
+    let own_counts = generics.own_counts();
 
     let gen_count_ok = |found: usize, expected: usize, descr: &str| -> bool {
         if found != expected {
@@ -57,9 +55,17 @@ fn equate_intrinsic_type<'tcx>(
         }
     };
 
+    // the host effect param should be invisible as it shouldn't matter
+    // whether effects is enabled for the intrinsic provider crate.
+    let consts_count = if generics.host_effect_index.is_some() {
+        own_counts.consts - 1
+    } else {
+        own_counts.consts
+    };
+
     if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime")
         && gen_count_ok(own_counts.types, n_tps, "type")
-        && gen_count_ok(own_counts.consts, n_cts, "const")
+        && gen_count_ok(consts_count, n_cts, "const")
     {
         let _ = check_function_signature(
             tcx,
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 8469cbbbc7d..6a36938dd1d 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -96,10 +96,10 @@ use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::suggestions::{
+use rustc_trait_selection::error_reporting::traits::suggestions::{
     ReturnsVisitor, TypeErrCtxtExt as _,
 };
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::errors;
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 2230528a5ae..b2ef07d65c5 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -29,8 +29,8 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::misc::{
     type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError,
 };
@@ -39,6 +39,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _
 use rustc_trait_selection::traits::{
     self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
 };
+use rustc_type_ir::solve::NoSolution;
 use rustc_type_ir::TypeFlags;
 
 use std::cell::LazyCell;
@@ -477,7 +478,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
                             param_env,
                             item_def_id,
                             tcx.explicit_item_bounds(item_def_id)
-                                .instantiate_identity_iter_copied()
+                                .iter_identity_copied()
                                 .collect::<Vec<_>>(),
                             &FxIndexSet::default(),
                             gat_def_id,
@@ -1204,17 +1205,16 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt
     let bounds = wfcx.tcx().explicit_item_bounds(item.def_id);
 
     debug!("check_associated_type_bounds: bounds={:?}", bounds);
-    let wf_obligations =
-        bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| {
-            let normalized_bound = wfcx.normalize(span, None, bound);
-            traits::wf::clause_obligations(
-                wfcx.infcx,
-                wfcx.param_env,
-                wfcx.body_def_id,
-                normalized_bound,
-                bound_span,
-            )
-        });
+    let wf_obligations = bounds.iter_identity_copied().flat_map(|(bound, bound_span)| {
+        let normalized_bound = wfcx.normalize(span, None, bound);
+        traits::wf::clause_obligations(
+            wfcx.infcx,
+            wfcx.param_env,
+            wfcx.body_def_id,
+            normalized_bound,
+            bound_span,
+        )
+    });
 
     wfcx.register_obligations(wf_obligations);
 }
@@ -1712,13 +1712,12 @@ fn receiver_is_valid<'tcx>(
     let cause =
         ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver);
 
-    let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty);
-
-    // `self: Self` is always valid.
-    if can_eq_self(receiver_ty) {
-        if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) {
-            infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
-        }
+    // Special case `receiver == self_ty`, which doesn't necessarily require the `Receiver` lang item.
+    if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
+        let ocx = ObligationCtxt::new(wfcx.infcx);
+        ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?;
+        if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
+    }) {
         return true;
     }
 
@@ -1729,58 +1728,51 @@ fn receiver_is_valid<'tcx>(
         autoderef = autoderef.include_raw_pointers();
     }
 
-    // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it.
-    autoderef.next();
-
     let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span));
 
     // Keep dereferencing `receiver_ty` until we get to `self_ty`.
-    loop {
-        if let Some((potential_self_ty, _)) = autoderef.next() {
-            debug!(
-                "receiver_is_valid: potential self type `{:?}` to match `{:?}`",
-                potential_self_ty, self_ty
-            );
-
-            if can_eq_self(potential_self_ty) {
-                wfcx.register_obligations(autoderef.into_obligations());
+    while let Some((potential_self_ty, _)) = autoderef.next() {
+        debug!(
+            "receiver_is_valid: potential self type `{:?}` to match `{:?}`",
+            potential_self_ty, self_ty
+        );
 
-                if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) {
-                    infcx
-                        .err_ctxt()
-                        .report_mismatched_types(&cause, self_ty, potential_self_ty, err)
-                        .emit();
-                }
+        // Check if the self type unifies. If it does, then commit the result
+        // since it may have region side-effects.
+        if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
+            let ocx = ObligationCtxt::new(wfcx.infcx);
+            ocx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty)?;
+            if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
+        }) {
+            wfcx.register_obligations(autoderef.into_obligations());
+            return true;
+        }
 
+        // Without `feature(arbitrary_self_types)`, we require that each step in the
+        // deref chain implement `receiver`.
+        if !arbitrary_self_types_enabled {
+            if !receiver_is_implemented(
+                wfcx,
+                receiver_trait_def_id,
+                cause.clone(),
+                potential_self_ty,
+            ) {
+                // We cannot proceed.
                 break;
-            } else {
-                // Without `feature(arbitrary_self_types)`, we require that each step in the
-                // deref chain implement `receiver`
-                if !arbitrary_self_types_enabled
-                    && !receiver_is_implemented(
-                        wfcx,
-                        receiver_trait_def_id,
-                        cause.clone(),
-                        potential_self_ty,
-                    )
-                {
-                    return false;
-                }
             }
-        } else {
-            debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
-            return false;
-        }
-    }
 
-    // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`.
-    if !arbitrary_self_types_enabled
-        && !receiver_is_implemented(wfcx, receiver_trait_def_id, cause.clone(), receiver_ty)
-    {
-        return false;
+            // Register the bound, in case it has any region side-effects.
+            wfcx.register_bound(
+                cause.clone(),
+                wfcx.param_env,
+                potential_self_ty,
+                receiver_trait_def_id,
+            );
+        }
     }
 
-    true
+    debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
+    false
 }
 
 fn receiver_is_implemented<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 61adb7a3cba..2ecb170ec89 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::traits::misc::{
     type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
     ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 5cb91603fd0..16f72f38d60 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -286,7 +286,7 @@ fn orphan_check<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_def_id: LocalDefId,
     mode: OrphanCheckMode,
-) -> Result<(), OrphanCheckErr<'tcx, FxIndexSet<DefId>>> {
+) -> Result<(), OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>> {
     // We only accept this routine to be invoked on implementations
     // of a trait, not inherent implementations.
     let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
@@ -326,17 +326,16 @@ fn orphan_check<'tcx>(
             ty
         };
 
-        Ok(ty)
+        Ok::<_, !>(ty)
     };
 
-    let Ok(result) = traits::orphan_check_trait_ref::<!>(
+    let result = traits::orphan_check_trait_ref(
         &infcx,
         trait_ref,
         traits::InCrate::Local { mode },
         lazily_normalize_ty,
-    ) else {
-        unreachable!()
-    };
+    )
+    .into_ok();
 
     // (2)  Try to map the remaining inference vars back to generic params.
     result.map_err(|err| match err {
@@ -369,7 +368,7 @@ fn emit_orphan_check_error<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     impl_def_id: LocalDefId,
-    err: traits::OrphanCheckErr<'tcx, FxIndexSet<DefId>>,
+    err: traits::OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>,
 ) -> ErrorGuaranteed {
     match err {
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
@@ -482,7 +481,7 @@ fn emit_orphan_check_error<'tcx>(
 
 fn lint_uncovered_ty_params<'tcx>(
     tcx: TyCtxt<'tcx>,
-    UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<'tcx, FxIndexSet<DefId>>,
+    UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<TyCtxt<'tcx>, FxIndexSet<DefId>>,
     impl_def_id: LocalDefId,
 ) {
     let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 41fbef48940..632ab3120d0 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -18,7 +18,9 @@ use rustc_ast::Recovered;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::unord::UnordMap;
-use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228};
+use rustc_errors::{
+    struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, StashKey, E0228,
+};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, walk_generics, Visitor};
@@ -35,8 +37,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::FieldIdx;
 use rustc_target::spec::abi;
+use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 use rustc_trait_selection::traits::ObligationCtxt;
 use std::cell::Cell;
 use std::iter;
@@ -161,7 +163,7 @@ pub struct CollectItemTypesVisitor<'tcx> {
 /// and suggest adding type parameters in the appropriate place, taking into consideration any and
 /// all already existing generic type parameters to avoid suggesting a name that is already in use.
 pub(crate) fn placeholder_type_error<'tcx>(
-    tcx: TyCtxt<'tcx>,
+    cx: &dyn HirTyLowerer<'tcx>,
     generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
     suggest: bool,
@@ -172,21 +174,21 @@ pub(crate) fn placeholder_type_error<'tcx>(
         return;
     }
 
-    placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
+    placeholder_type_error_diag(cx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
         .emit();
 }
 
-pub(crate) fn placeholder_type_error_diag<'tcx>(
-    tcx: TyCtxt<'tcx>,
+pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>(
+    cx: &'cx dyn HirTyLowerer<'tcx>,
     generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
     additional_spans: Vec<Span>,
     suggest: bool,
     hir_ty: Option<&hir::Ty<'_>>,
     kind: &'static str,
-) -> Diag<'tcx> {
+) -> Diag<'cx> {
     if placeholder_types.is_empty() {
-        return bad_placeholder(tcx, additional_spans, kind);
+        return bad_placeholder(cx, additional_spans, kind);
     }
 
     let params = generics.map(|g| g.params).unwrap_or_default();
@@ -210,7 +212,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
     }
 
     let mut err =
-        bad_placeholder(tcx, placeholder_types.into_iter().chain(additional_spans).collect(), kind);
+        bad_placeholder(cx, placeholder_types.into_iter().chain(additional_spans).collect(), kind);
 
     // Suggest, but only if it is not a function in const or static
     if suggest {
@@ -224,7 +226,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
 
             // Check if parent is const or static
             is_const_or_static = matches!(
-                tcx.parent_hir_node(hir_ty.hir_id),
+                cx.tcx().parent_hir_node(hir_ty.hir_id),
                 Node::Item(&hir::Item {
                     kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
                     ..
@@ -267,7 +269,16 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
     let mut visitor = HirPlaceholderCollector::default();
     visitor.visit_item(item);
 
-    placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr());
+    let icx = ItemCtxt::new(tcx, item.owner_id.def_id);
+
+    placeholder_type_error(
+        icx.lowerer(),
+        Some(generics),
+        visitor.0,
+        suggest,
+        None,
+        item.kind.descr(),
+    );
 }
 
 impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
@@ -329,15 +340,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Utility types and common code for the above passes.
 
-fn bad_placeholder<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn bad_placeholder<'cx, 'tcx>(
+    cx: &'cx dyn HirTyLowerer<'tcx>,
     mut spans: Vec<Span>,
     kind: &'static str,
-) -> Diag<'tcx> {
+) -> Diag<'cx> {
     let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") };
 
     spans.sort();
-    tcx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
+    cx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
 }
 
 impl<'tcx> ItemCtxt<'tcx> {
@@ -370,6 +381,10 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
         self.tcx
     }
 
+    fn dcx(&self) -> DiagCtxtHandle<'_> {
+        self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
+    }
+
     fn item_def_id(&self) -> LocalDefId {
         self.item_def_id
     }
@@ -377,14 +392,13 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
     fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
         if let RegionInferReason::BorrowedObjectLifetimeDefault = reason {
             let e = struct_span_code_err!(
-                self.tcx().dcx(),
+                self.dcx(),
                 span,
                 E0228,
                 "the lifetime bound for this object type cannot be deduced \
                 from context; please supply an explicit bound"
             )
             .emit();
-            self.set_tainted_by_errors(e);
             ty::Region::new_error(self.tcx(), e)
         } else {
             // This indicates an illegal lifetime in a non-assoc-trait position
@@ -509,10 +523,6 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
         None
     }
 
-    fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
-        self.tainted_by_errors.set(Some(err));
-    }
-
     fn lower_fn_sig(
         &self,
         decl: &hir::FnDecl<'tcx>,
@@ -570,7 +580,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
             // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
 
             let mut diag = crate::collect::placeholder_type_error_diag(
-                tcx,
+                self,
                 generics,
                 visitor.0,
                 infer_replacements.iter().map(|(s, _)| *s).collect(),
@@ -590,7 +600,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                 );
             }
 
-            self.set_tainted_by_errors(diag.emit());
+            diag.emit();
         }
 
         (input_tys, output_ty)
@@ -639,6 +649,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
     let it = tcx.hir().item(item_id);
     debug!(item = %it.ident, id = %it.hir_id());
     let def_id = item_id.owner_id.def_id;
+    let icx = ItemCtxt::new(tcx, def_id);
 
     match &it.kind {
         // These don't define types.
@@ -663,7 +674,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                         let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_foreign_item(item);
                         placeholder_type_error(
-                            tcx,
+                            icx.lowerer(),
                             None,
                             visitor.0,
                             false,
@@ -742,7 +753,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             if !ty.is_suggestable_infer_ty() {
                 let mut visitor = HirPlaceholderCollector::default();
                 visitor.visit_item(it);
-                placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
+                placeholder_type_error(
+                    icx.lowerer(),
+                    None,
+                    visitor.0,
+                    false,
+                    None,
+                    it.kind.descr(),
+                );
             }
         }
 
@@ -760,6 +778,7 @@ 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);
+    let icx = ItemCtxt::new(tcx, def_id.def_id);
 
     match trait_item.kind {
         hir::TraitItemKind::Fn(..) => {
@@ -776,7 +795,14 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
                 // Account for `const C: _;`.
                 let mut visitor = HirPlaceholderCollector::default();
                 visitor.visit_trait_item(trait_item);
-                placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
+                placeholder_type_error(
+                    icx.lowerer(),
+                    None,
+                    visitor.0,
+                    false,
+                    None,
+                    "associated constant",
+                );
             }
         }
 
@@ -787,7 +813,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             // Account for `type T = _;`.
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
+            placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type");
         }
 
         hir::TraitItemKind::Type(_, None) => {
@@ -798,7 +824,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
 
-            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
+            placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type");
         }
     };
 
@@ -811,6 +837,7 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
     tcx.ensure().type_of(def_id);
     tcx.ensure().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);
@@ -821,14 +848,21 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_impl_item(impl_item);
 
-            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
+            placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type");
         }
         hir::ImplItemKind::Const(ty, _) => {
             // Account for `const T: _ = ..;`
             if !ty.is_suggestable_infer_ty() {
                 let mut visitor = HirPlaceholderCollector::default();
                 visitor.visit_impl_item(impl_item);
-                placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
+                placeholder_type_error(
+                    icx.lowerer(),
+                    None,
+                    visitor.0,
+                    false,
+                    None,
+                    "associated constant",
+                );
             }
         }
     }
@@ -1194,6 +1228,11 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
+    let constness = if tcx.has_attr(def_id, sym::const_trait) {
+        hir::Constness::Const
+    } else {
+        hir::Constness::NotConst
+    };
     let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
     if paren_sugar && !tcx.features().unboxed_closures {
         tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span });
@@ -1201,6 +1240,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
 
     let is_marker = tcx.has_attr(def_id, sym::marker);
     let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
+    let is_fundamental = tcx.has_attr(def_id, sym::fundamental);
 
     // FIXME: We could probably do way better attribute validation here.
     let mut skip_array_during_method_dispatch = false;
@@ -1348,10 +1388,12 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     ty::TraitDef {
         def_id: def_id.to_def_id(),
         safety,
+        constness,
         paren_sugar,
         has_auto_impl: is_auto,
         is_marker,
         is_coinductive: rustc_coinductive || is_auto,
+        is_fundamental,
         skip_array_during_method_dispatch,
         skip_boxed_slice_during_method_dispatch,
         specialization_kind,
@@ -1377,7 +1419,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
             ..
         })
         | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
-            infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
+            infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
         }
 
         ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
@@ -1394,7 +1436,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
                     None,
                 )
             } else {
-                infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
+                infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
             }
         }
 
@@ -1447,12 +1489,12 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
 }
 
 fn infer_return_ty_for_fn_sig<'tcx>(
-    tcx: TyCtxt<'tcx>,
     sig: &hir::FnSig<'tcx>,
     generics: &hir::Generics<'_>,
     def_id: LocalDefId,
     icx: &ItemCtxt<'tcx>,
 ) -> ty::PolyFnSig<'tcx> {
+    let tcx = icx.tcx;
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
 
     match sig.decl.output.get_infer_ret_ty() {
@@ -1484,7 +1526,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_ty(ty);
 
-            let mut diag = bad_placeholder(tcx, visitor.0, "return type");
+            let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
             let ret_ty = fn_sig.output();
             // Don't leak types into signatures unless they're nameable!
             // For example, if a function returns itself, we don't want that
@@ -1680,7 +1722,7 @@ fn check_impl_constness(
     }
 
     let trait_def_id = hir_trait_ref.trait_def_id()?;
-    if tcx.has_attr(trait_def_id, sym::const_trait) {
+    if tcx.is_const_trait(trait_def_id) {
         return None;
     }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 9b02c1a61fa..22d465c8e62 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -1,3 +1,5 @@
+use std::ops::ControlFlow;
+
 use crate::middle::resolve_bound_vars as rbv;
 use hir::{
     intravisit::{self, Visitor},
@@ -87,14 +89,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
             let mut in_param_ty = false;
             for (_parent, node) in tcx.hir().parent_iter(hir_id) {
                 if let Some(generics) = node.generics() {
-                    let mut visitor = AnonConstInParamTyDetector {
-                        in_param_ty: false,
-                        found_anon_const_in_param_ty: false,
-                        ct: hir_id,
-                    };
+                    let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id };
 
-                    visitor.visit_generics(generics);
-                    in_param_ty = visitor.found_anon_const_in_param_ty;
+                    in_param_ty = visitor.visit_generics(generics).is_break();
                     break;
                 }
             }
@@ -460,50 +457,45 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
     struct LateBoundRegionsDetector<'tcx> {
         tcx: TyCtxt<'tcx>,
         outer_index: ty::DebruijnIndex,
-        has_late_bound_regions: Option<Span>,
     }
 
     impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
-        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
+        type Result = ControlFlow<Span>;
+        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> {
             match ty.kind {
                 hir::TyKind::BareFn(..) => {
                     self.outer_index.shift_in(1);
-                    intravisit::walk_ty(self, ty);
+                    let res = intravisit::walk_ty(self, ty);
                     self.outer_index.shift_out(1);
+                    res
                 }
                 _ => intravisit::walk_ty(self, ty),
             }
         }
 
-        fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
+        fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow<Span> {
             self.outer_index.shift_in(1);
-            intravisit::walk_poly_trait_ref(self, tr);
+            let res = intravisit::walk_poly_trait_ref(self, tr);
             self.outer_index.shift_out(1);
+            res
         }
 
-        fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
-            if self.has_late_bound_regions.is_some() {
-                return;
-            }
-
+        fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow<Span> {
             match self.tcx.named_bound_var(lt.hir_id) {
-                Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {}
+                Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {
+                    ControlFlow::Continue(())
+                }
                 Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
-                    if debruijn < self.outer_index => {}
+                    if debruijn < self.outer_index =>
+                {
+                    ControlFlow::Continue(())
+                }
                 Some(
                     rbv::ResolvedArg::LateBound(..)
                     | rbv::ResolvedArg::Free(..)
                     | rbv::ResolvedArg::Error(_),
                 )
-                | None => {
-                    self.has_late_bound_regions = Some(lt.ident.span);
-                }
+                | None => ControlFlow::Break(lt.ident.span),
             }
         }
     }
@@ -513,11 +505,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
         generics: &'tcx hir::Generics<'tcx>,
         decl: &'tcx hir::FnDecl<'tcx>,
     ) -> Option<Span> {
-        let mut visitor = LateBoundRegionsDetector {
-            tcx,
-            outer_index: ty::INNERMOST,
-            has_late_bound_regions: None,
-        };
+        let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST };
         for param in generics.params {
             if let GenericParamKind::Lifetime { .. } = param.kind {
                 if tcx.is_late_bound(param.hir_id) {
@@ -525,8 +513,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
                 }
             }
         }
-        visitor.visit_fn_decl(decl);
-        visitor.has_late_bound_regions
+        visitor.visit_fn_decl(decl).break_value()
     }
 
     let decl = node.fn_decl()?;
@@ -536,26 +523,29 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
 
 struct AnonConstInParamTyDetector {
     in_param_ty: bool,
-    found_anon_const_in_param_ty: bool,
     ct: HirId,
 }
 
 impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
-    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
+    type Result = ControlFlow<()>;
+
+    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result {
         if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
         {
             let prev = self.in_param_ty;
             self.in_param_ty = true;
-            self.visit_ty(ty);
+            let res = self.visit_ty(ty);
             self.in_param_ty = prev;
+            res
+        } else {
+            ControlFlow::Continue(())
         }
     }
 
-    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
+    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> Self::Result {
         if self.in_param_ty && self.ct == c.hir_id {
-            self.found_anon_const_in_param_ty = true;
-        } else {
-            intravisit::walk_anon_const(self, c)
+            return ControlFlow::Break(());
         }
+        intravisit::walk_anon_const(self, c)
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 1e2b0c43233..974dd415f46 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -12,6 +12,7 @@ use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
 use crate::errors::TypeofReservedKeywordUsed;
+use crate::hir_ty_lowering::HirTyLowerer;
 
 use super::bad_placeholder;
 use super::ItemCtxt;
@@ -357,7 +358,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
                 .and_then(|body_id| {
                     ty.is_suggestable_infer_ty().then(|| {
                         infer_placeholder_type(
-                            tcx,
+                            icx.lowerer(),
                             def_id,
                             body_id,
                             ty.span,
@@ -381,7 +382,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
             ImplItemKind::Const(ty, body_id) => {
                 if ty.is_suggestable_infer_ty() {
                     infer_placeholder_type(
-                        tcx,
+                        icx.lowerer(),
                         def_id,
                         body_id,
                         ty.span,
@@ -405,7 +406,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
             ItemKind::Static(ty, .., body_id) => {
                 if ty.is_suggestable_infer_ty() {
                     infer_placeholder_type(
-                        tcx,
+                        icx.lowerer(),
                         def_id,
                         body_id,
                         ty.span,
@@ -418,7 +419,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
             }
             ItemKind::Const(ty, _, body_id) => {
                 if ty.is_suggestable_infer_ty() {
-                    infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
+                    infer_placeholder_type(
+                        icx.lowerer(),
+                        def_id,
+                        body_id,
+                        ty.span,
+                        item.ident,
+                        "constant",
+                    )
                 } else {
                     icx.lower_ty(ty)
                 }
@@ -559,21 +567,22 @@ pub(super) fn type_of_opaque(
     }
 }
 
-fn infer_placeholder_type<'a>(
-    tcx: TyCtxt<'a>,
+fn infer_placeholder_type<'tcx>(
+    cx: &dyn HirTyLowerer<'tcx>,
     def_id: LocalDefId,
     body_id: hir::BodyId,
     span: Span,
     item_ident: Ident,
     kind: &'static str,
-) -> Ty<'a> {
+) -> Ty<'tcx> {
+    let tcx = cx.tcx();
     let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
 
     // If this came from a free `const` or `static mut?` item,
     // then the user may have written e.g. `const A = 42;`.
     // In this case, the parser has stashed a diagnostic for
     // us to improve in typeck so we do that now.
-    let guar = tcx
+    let guar = cx
         .dcx()
         .try_steal_modify_and_emit_err(span, StashKey::ItemNoType, |err| {
             if !ty.references_error() {
@@ -602,7 +611,7 @@ fn infer_placeholder_type<'a>(
             }
         })
         .unwrap_or_else(|| {
-            let mut diag = bad_placeholder(tcx, vec![span], kind);
+            let mut diag = bad_placeholder(cx, vec![span], kind);
 
             if !ty.references_error() {
                 if let Some(ty) = ty.make_suggestable(tcx, false, None) {
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 3ffb51fa992..0ee87a13e9e 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -9,6 +9,7 @@ use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 mod pattern_types;
 pub use pattern_types::*;
+pub mod wrong_number_of_generic_args;
 
 mod precise_captures;
 pub(crate) use precise_captures::*;
@@ -453,12 +454,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams {
             } else {
                 // The user wrote `Iterator`, so we don't have a type we can suggest, but at
                 // least we can clue them to the correct syntax `Iterator<Type>`.
-                err.span_suggestion(
-                    self.span,
+                err.span_suggestion_verbose(
+                    self.span.shrink_to_hi(),
                     fluent::hir_analysis_suggestion,
                     format!(
-                        "{}<{}>",
-                        snippet,
+                        "<{}>",
                         self.missing_type_params
                             .iter()
                             .map(|n| n.to_string())
@@ -694,29 +694,6 @@ pub(crate) struct TypeOf<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_pass_to_variadic_function, code = E0617)]
-pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
-    #[primary_span]
-    pub span: Span,
-    pub ty: Ty<'tcx>,
-    pub cast_ty: &'a str,
-    #[suggestion(code = "{replace}", applicability = "machine-applicable")]
-    pub sugg_span: Option<Span>,
-    pub replace: String,
-    #[help]
-    pub help: Option<()>,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = E0607)]
-pub(crate) struct CastThinPointerToFatPointer<'tcx> {
-    #[primary_span]
-    pub span: Span,
-    pub expr_ty: Ty<'tcx>,
-    pub cast_ty: String,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_invalid_union_field, code = E0740)]
 pub(crate) struct InvalidUnionField {
     #[primary_span]
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index 5d435a8edf9..6426ad9dc18 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -1,8 +1,8 @@
-use crate::structured_errors::StructuredDiag;
-use rustc_errors::{codes::*, pluralize, Applicability, Diag, MultiSpan};
+use rustc_errors::{
+    codes::*, pluralize, Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
-use rustc_session::Session;
 use rustc_span::def_id::DefId;
 use std::iter;
 
@@ -541,14 +541,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
-    fn start_diagnostics(&self) -> Diag<'tcx> {
-        let span = self.path_segment.ident.span;
-        let msg = self.create_error_message();
-        self.tcx.dcx().struct_span_err(span, msg).with_code(self.code())
-    }
-
     /// Builds the `expected 1 type argument / supplied 2 type arguments` message.
-    fn notify(&self, err: &mut Diag<'_>) {
+    fn notify(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         let (quantifier, bound) = self.get_quantifier_and_bound();
         let provided_args = self.num_provided_args();
 
@@ -600,7 +594,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
-    fn suggest(&self, err: &mut Diag<'_>) {
+    fn suggest(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         debug!(
             "suggest(self.provided {:?}, self.gen_args.span(): {:?})",
             self.num_provided_args(),
@@ -628,7 +622,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     /// ```text
     /// type Map = HashMap<String>;
     /// ```
-    fn suggest_adding_args(&self, err: &mut Diag<'_>) {
+    fn suggest_adding_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         if self.gen_args.parenthesized != hir::GenericArgsParentheses::No {
             return;
         }
@@ -647,7 +641,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
-    fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_>) {
+    fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment);
         let num_missing_args = self.num_missing_lifetime_args();
         let num_params_to_take = num_missing_args;
@@ -701,7 +695,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
-    fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_>) {
+    fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         let num_missing_args = self.num_missing_type_or_const_args();
         let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
 
@@ -761,7 +755,10 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     /// ```compile_fail
     /// Into::into::<Option<_>>(42) // suggests considering `Into::<Option<_>>::into(42)`
     /// ```
-    fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diag<'_>) {
+    fn suggest_moving_args_from_assoc_fn_to_trait(
+        &self,
+        err: &mut Diag<'_, impl EmissionGuarantee>,
+    ) {
         let trait_ = match self.tcx.trait_of_item(self.def_id) {
             Some(def_id) => def_id,
             None => return,
@@ -817,7 +814,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
 
     fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
         &self,
-        err: &mut Diag<'_>,
+        err: &mut Diag<'_, impl EmissionGuarantee>,
         qpath: &'tcx hir::QPath<'tcx>,
         msg: String,
         num_assoc_fn_excess_args: usize,
@@ -850,7 +847,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
 
     fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
         &self,
-        err: &mut Diag<'_>,
+        err: &mut Diag<'_, impl EmissionGuarantee>,
         trait_def_id: DefId,
         expr: &'tcx hir::Expr<'tcx>,
         msg: String,
@@ -904,7 +901,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     /// ```text
     /// type Map = HashMap<String, String, String, String>;
     /// ```
-    fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_>) {
+    fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         let num_provided_lt_args = self.num_provided_lifetime_args();
         let num_provided_type_const_args = self.num_provided_type_or_const_args();
         let unbound_types = self.get_unbound_associated_types();
@@ -922,7 +919,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         let provided_args_matches_unbound_traits =
             unbound_types.len() == num_redundant_type_or_const_args;
 
-        let remove_lifetime_args = |err: &mut Diag<'_>| {
+        let remove_lifetime_args = |err: &mut Diag<'_, _>| {
             let mut lt_arg_spans = Vec::new();
             let mut found_redundant = false;
             for arg in self.gen_args.args {
@@ -963,7 +960,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             );
         };
 
-        let remove_type_or_const_args = |err: &mut Diag<'_>| {
+        let remove_type_or_const_args = |err: &mut Diag<'_, _>| {
             let mut gen_arg_spans = Vec::new();
             let mut found_redundant = false;
             for arg in self.gen_args.args {
@@ -1060,7 +1057,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     }
 
     /// Builds the `type defined here` message.
-    fn show_definition(&self, err: &mut Diag<'_>) {
+    fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
             if self.tcx.sess.source_map().is_span_accessible(def_span) {
                 def_span.into()
@@ -1111,7 +1108,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     }
 
     /// Add note if `impl Trait` is explicitly specified.
-    fn note_synth_provided(&self, err: &mut Diag<'_>) {
+    fn note_synth_provided(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
         if !self.is_synth_provided() {
             return;
         }
@@ -1120,17 +1117,16 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     }
 }
 
-impl<'tcx> StructuredDiag<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> {
-    fn session(&self) -> &Session {
-        self.tcx.sess
-    }
-
-    fn code(&self) -> ErrCode {
-        E0107
-    }
-
-    fn diagnostic_common(&self) -> Diag<'tcx> {
-        let mut err = self.start_diagnostics();
+impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for WrongNumberOfGenericArgs<'_, '_> {
+    fn into_diag(
+        self,
+        dcx: rustc_errors::DiagCtxtHandle<'a>,
+        level: rustc_errors::Level,
+    ) -> Diag<'a, G> {
+        let msg = self.create_error_message();
+        let mut err = Diag::new(dcx, level, msg);
+        err.code(E0107);
+        err.span(self.path_segment.ident.span);
 
         self.notify(&mut err);
         self.suggest(&mut err);
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 802215b2843..a1feef9e15b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -76,7 +76,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
 
         if unbounds.len() > 1 {
-            tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
+            self.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
                 spans: unbounds.iter().map(|ptr| ptr.span).collect(),
             });
         }
@@ -90,7 +90,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 continue;
             }
             // There was a `?Trait` bound, but it was not `?Sized`; warn.
-            tcx.dcx().span_warn(
+            self.dcx().span_warn(
                 unbound.span,
                 "relaxing a default bound only does something for `?Sized`; \
                 all other traits are not bound by default",
@@ -310,7 +310,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         duplicates
             .entry(assoc_item.def_id)
             .and_modify(|prev_span| {
-                tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
+                self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
                     span: constraint.span,
                     prev_span: *prev_span,
                     item_name: constraint.ident,
@@ -338,7 +338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         .into(),
                         ty::GenericParamDefKind::Type { .. } => {
                             let guar = *emitted_bad_param_err.get_or_insert_with(|| {
-                                tcx.dcx().emit_err(
+                                self.dcx().emit_err(
                                     crate::errors::ReturnTypeNotationIllegalParam::Type {
                                         span: path_span,
                                         param_span: tcx.def_span(param.def_id),
@@ -349,7 +349,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         }
                         ty::GenericParamDefKind::Const { .. } => {
                             let guar = *emitted_bad_param_err.get_or_insert_with(|| {
-                                tcx.dcx().emit_err(
+                                self.dcx().emit_err(
                                     crate::errors::ReturnTypeNotationIllegalParam::Const {
                                         span: path_span,
                                         param_span: tcx.def_span(param.def_id),
@@ -371,7 +371,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             {
                 alias_ty.into()
             } else {
-                return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
+                return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
                     span: constraint.span,
                     ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
                     fn_span: tcx.hir().span_if_local(assoc_item.def_id),
@@ -417,7 +417,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let ty = alias_term
                     .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
                 let ty =
-                    check_assoc_const_binding_type(tcx, constraint.ident, ty, constraint.hir_id);
+                    check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id);
                 tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
             }
 
@@ -426,7 +426,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         match constraint.kind {
             hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
-                return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
+                return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
                     span: constraint.span,
                 }));
             }
@@ -462,7 +462,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     late_bound_in_term,
                     |br_name| {
                         struct_span_code_err!(
-                            tcx.dcx(),
+                            self.dcx(),
                             constraint.span,
                             E0582,
                             "binding for associated type `{}` references {}, \
@@ -519,7 +519,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 ///
 /// [^1]: <https://github.com/rust-lang/project-const-generics/issues/28>.
 fn check_assoc_const_binding_type<'tcx>(
-    tcx: TyCtxt<'tcx>,
+    cx: &dyn HirTyLowerer<'tcx>,
     assoc_const: Ident,
     ty: ty::Binder<'tcx, Ty<'tcx>>,
     hir_id: hir::HirId,
@@ -536,13 +536,14 @@ fn check_assoc_const_binding_type<'tcx>(
     }
 
     let mut collector = GenericParamAndBoundVarCollector {
-        tcx,
+        cx,
         params: Default::default(),
         vars: Default::default(),
         depth: ty::INNERMOST,
     };
     let mut guar = ty.visit_with(&mut collector).break_value();
 
+    let tcx = cx.tcx();
     let ty_note = ty
         .make_suggestable(tcx, false, None)
         .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty });
@@ -556,7 +557,7 @@ fn check_assoc_const_binding_type<'tcx>(
     for index in collector.params {
         let param = generics.param_at(index as _, tcx);
         let is_self_param = param.name == rustc_span::symbol::kw::SelfUpper;
-        guar.get_or_insert(tcx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding {
+        guar.get_or_insert(cx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding {
             span: assoc_const.span,
             assoc_const,
             param_name: param.name,
@@ -574,7 +575,7 @@ fn check_assoc_const_binding_type<'tcx>(
         }));
     }
     for (var_def_id, var_name) in collector.vars {
-        guar.get_or_insert(tcx.dcx().emit_err(
+        guar.get_or_insert(cx.dcx().emit_err(
             crate::errors::EscapingBoundVarInTyOfAssocConstBinding {
                 span: assoc_const.span,
                 assoc_const,
@@ -590,14 +591,14 @@ fn check_assoc_const_binding_type<'tcx>(
     Ty::new_error(tcx, guar)
 }
 
-struct GenericParamAndBoundVarCollector<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct GenericParamAndBoundVarCollector<'a, 'tcx> {
+    cx: &'a dyn HirTyLowerer<'tcx>,
     params: FxIndexSet<u32>,
     vars: FxIndexSet<(DefId, Symbol)>,
     depth: ty::DebruijnIndex,
 }
 
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> {
     type Result = ControlFlow<ErrorGuaranteed>;
 
     fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
@@ -620,7 +621,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx>
                     ty::BoundTyKind::Param(def_id, name) => (def_id, name),
                     ty::BoundTyKind::Anon => {
                         let reported = self
-                            .tcx
+                            .cx
                             .dcx()
                             .delayed_bug(format!("unexpected anon bound ty: {:?}", bt.var));
                         return ControlFlow::Break(reported);
@@ -643,7 +644,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx>
                     ty::BrNamed(def_id, name) => (def_id, name),
                     ty::BrAnon | ty::BrEnv => {
                         let guar = self
-                            .tcx
+                            .cx
                             .dcx()
                             .delayed_bug(format!("unexpected bound region kind: {:?}", br.kind));
                         return ControlFlow::Break(guar);
@@ -661,7 +662,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx>
                 self.params.insert(param.index);
             }
             ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => {
-                let guar = self.tcx.dcx().delayed_bug("unexpected escaping late-bound const var");
+                let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var");
                 return ControlFlow::Break(guar);
             }
             _ if ct.has_param() || ct.has_bound_vars() => return ct.super_visit_with(self),
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 2d240699105..ebd2a63d555 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -4,7 +4,6 @@ use crate::errors::{
 };
 use crate::fluent_generated as fluent;
 use crate::hir_ty_lowering::HirTyLowerer;
-use crate::traits::error_reporting::report_object_safety_error;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
@@ -27,6 +26,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::BytePos;
 use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_trait_selection::error_reporting::traits::report_object_safety_error;
 use rustc_trait_selection::traits::FulfillmentError;
 use rustc_trait_selection::traits::{
     object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
@@ -46,7 +46,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             return;
         }
 
-        self.tcx().dcx().emit_err(MissingTypeParams {
+        self.dcx().emit_err(MissingTypeParams {
             span,
             def_span: self.tcx().def_span(def_id),
             span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
@@ -109,7 +109,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         if is_impl {
             let trait_name = self.tcx().def_path_str(trait_def_id);
-            self.tcx().dcx().emit_err(ManualImplementation { span, trait_name });
+            self.dcx().emit_err(ManualImplementation { span, trait_name });
         }
     }
 
@@ -156,7 +156,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         if is_dummy {
             err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
-            return tcx.dcx().emit_err(err);
+            return self.dcx().emit_err(err);
         }
 
         let all_candidate_names: Vec<_> = all_candidates()
@@ -174,7 +174,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 assoc_kind: assoc_kind_str,
                 suggested_name,
             });
-            return tcx.dcx().emit_err(err);
+            return self.dcx().emit_err(err);
         }
 
         // If we didn't find a good item in the supertraits (or couldn't get
@@ -239,10 +239,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             assoc_kind: assoc_kind_str,
                             suggested_name,
                         });
-                        return tcx.dcx().emit_err(err);
+                        return self.dcx().emit_err(err);
                     }
 
-                    let mut err = tcx.dcx().create_err(err);
+                    let mut err = self.dcx().create_err(err);
                     if suggest_constraining_type_param(
                         tcx,
                         generics,
@@ -264,7 +264,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     }
                     return err.emit();
                 }
-                return tcx.dcx().emit_err(err);
+                return self.dcx().emit_err(err);
             }
         }
 
@@ -291,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span });
         }
 
-        tcx.dcx().emit_err(err)
+        self.dcx().emit_err(err)
     }
 
     fn complain_about_assoc_kind_mismatch(
@@ -347,7 +347,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             (ident.span, None, assoc_kind, assoc_item.kind)
         };
 
-        tcx.dcx().emit_err(errors::AssocKindMismatch {
+        self.dcx().emit_err(errors::AssocKindMismatch {
             span,
             expected: super::assoc_kind_str(expected),
             got: super::assoc_kind_str(got),
@@ -366,8 +366,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         traits: &[String],
         name: Symbol,
     ) -> ErrorGuaranteed {
-        let mut err =
-            struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
+        let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type");
         if self
             .tcx()
             .resolutions(())
@@ -463,9 +462,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 }
             }
         }
-        let reported = err.emit();
-        self.set_tainted_by_errors(reported);
-        reported
+        err.emit()
     }
 
     pub(crate) fn complain_about_ambiguous_inherent_assoc_ty(
@@ -475,16 +472,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         span: Span,
     ) -> ErrorGuaranteed {
         let mut err = struct_span_code_err!(
-            self.tcx().dcx(),
+            self.dcx(),
             name.span,
             E0034,
             "multiple applicable items in scope"
         );
         err.span_label(name.span, format!("multiple `{name}` found"));
         self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span);
-        let reported = err.emit();
-        self.set_tainted_by_errors(reported);
-        reported
+        err.emit()
     }
 
     // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
@@ -576,7 +571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             };
 
             let mut err = struct_span_code_err!(
-                tcx.dcx(),
+                self.dcx(),
                 name.span,
                 E0220,
                 "associated type `{name}` not found for `{self_ty}` in the current scope"
@@ -662,7 +657,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         bounds.sort();
         bounds.dedup();
 
-        let mut err = tcx.dcx().struct_span_err(
+        let mut err = self.dcx().struct_span_err(
             name.span,
             format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
         );
@@ -829,7 +824,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         trait_bound_spans.sort();
         let mut err = struct_span_code_err!(
-            tcx.dcx(),
+            self.dcx(),
             trait_bound_spans,
             E0191,
             "the value of the associated type{} {} must be specified",
@@ -974,7 +969,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
-        self.set_tainted_by_errors(err.emit());
+        err.emit();
     }
 
     /// On ambiguous associated type, look for an associated function whose name matches the
@@ -1011,17 +1006,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 .filter_by_name_unhygienic(Symbol::intern(&name))
                 .next()
         {
-            let reported =
-                struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type")
-                    .with_span_suggestion_verbose(
-                        ident2.span.to(ident3.span),
-                        format!("there is an associated function with a similar name: `{name}`"),
-                        name,
-                        Applicability::MaybeIncorrect,
-                    )
-                    .emit();
-            self.set_tainted_by_errors(reported);
-            Err(reported)
+            Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
+                .with_span_suggestion_verbose(
+                    ident2.span.to(ident3.span),
+                    format!("there is an associated function with a similar name: `{name}`"),
+                    name,
+                    Applicability::MaybeIncorrect,
+                )
+                .emit())
         } else {
             Ok(())
         }
@@ -1120,7 +1112,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let last_span = *arg_spans.last().unwrap();
         let span: MultiSpan = arg_spans.into();
         let mut err = struct_span_code_err!(
-            self.tcx().dcx(),
+            self.dcx(),
             span,
             E0109,
             "{kind} arguments are not allowed on {this_type}",
@@ -1130,20 +1122,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             err.span_label(span, format!("not allowed on {what}"));
         }
         generics_args_err_extend(self.tcx(), segments, &mut err, err_extend);
-        let reported = err.emit();
-        self.set_tainted_by_errors(reported);
-        reported
+        err.emit()
     }
 
     pub fn report_trait_object_addition_traits_error(
         &self,
         regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
     ) -> ErrorGuaranteed {
-        let tcx = self.tcx();
         let first_trait = &regular_traits[0];
         let additional_trait = &regular_traits[1];
         let mut err = struct_span_code_err!(
-            tcx.dcx(),
+            self.dcx(),
             additional_trait.bottom().1,
             E0225,
             "only auto traits can be used as additional traits in a trait object"
@@ -1169,9 +1158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
              for more information on them, visit \
              <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
         );
-        let reported = err.emit();
-        self.set_tainted_by_errors(reported);
-        reported
+        err.emit()
     }
 
     pub fn report_trait_object_with_no_traits_error(
@@ -1185,20 +1172,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .map(|&(trait_ref, _)| trait_ref.def_id())
             .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
             .map(|trait_ref| tcx.def_span(trait_ref));
-        let reported =
-            tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
-        self.set_tainted_by_errors(reported);
-        reported
+
+        self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
     }
 }
 
 /// Emit an error for the given associated item constraint.
 pub fn prohibit_assoc_item_constraint(
-    tcx: TyCtxt<'_>,
+    cx: &dyn HirTyLowerer<'_>,
     constraint: &hir::AssocItemConstraint<'_>,
     segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
 ) -> ErrorGuaranteed {
-    let mut err = tcx.dcx().create_err(AssocItemConstraintsNotAllowedHere {
+    let tcx = cx.tcx();
+    let mut err = cx.dcx().create_err(AssocItemConstraintsNotAllowedHere {
         span: constraint.span,
         fn_trait_expansion: if let Some((_, segment, span)) = segment
             && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
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 e92c377f0ce..b1c77db9f37 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -1,9 +1,9 @@
-use super::IsMethodCall;
+use super::{HirTyLowerer, IsMethodCall};
+use crate::errors::wrong_number_of_generic_args::{GenericArgsInfo, WrongNumberOfGenericArgs};
 use crate::hir_ty_lowering::{
     errors::prohibit_assoc_item_constraint, ExplicitLateBound, GenericArgCountMismatch,
     GenericArgCountResult, GenericArgPosition, GenericArgsLowerer,
 };
-use crate::structured_errors::{GenericArgsInfo, StructuredDiag, WrongNumberOfGenericArgs};
 use rustc_ast::ast::ParamKindOrd;
 use rustc_errors::{
     codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
@@ -13,7 +13,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
 use rustc_middle::ty::{
-    self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
+    self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty,
 };
 use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
 use rustc_span::symbol::{kw, sym};
@@ -22,15 +22,16 @@ use smallvec::SmallVec;
 /// Report an error that a generic argument did not match the generic parameter that was
 /// expected.
 fn generic_arg_mismatch_err(
-    tcx: TyCtxt<'_>,
+    cx: &dyn HirTyLowerer<'_>,
     arg: &GenericArg<'_>,
     param: &GenericParamDef,
     possible_ordering_error: bool,
     help: Option<String>,
 ) -> ErrorGuaranteed {
+    let tcx = cx.tcx();
     let sess = tcx.sess;
     let mut err = struct_span_code_err!(
-        tcx.dcx(),
+        cx.dcx(),
         arg.span(),
         E0747,
         "{} provided when a {} was expected",
@@ -171,7 +172,7 @@ fn generic_arg_mismatch_err(
 /// - `inferred_kind`: if no parameter was provided, and inference
 ///   is enabled, then creates a suitable inference variable.
 pub fn lower_generic_args<'tcx: 'a, 'a>(
-    tcx: TyCtxt<'tcx>,
+    cx: &dyn HirTyLowerer<'tcx>,
     def_id: DefId,
     parent_args: &[ty::GenericArg<'tcx>],
     has_self: bool,
@@ -179,6 +180,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
     arg_count: &GenericArgCountResult,
     ctx: &mut impl GenericArgsLowerer<'a, 'tcx>,
 ) -> GenericArgsRef<'tcx> {
+    let tcx = cx.tcx();
     // Collect the segments of the path; we need to instantiate arguments
     // for parameters throughout the entire path (wherever there are
     // generic parameters).
@@ -326,7 +328,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                                 param_types_present.dedup();
 
                                 generic_arg_mismatch_err(
-                                    tcx,
+                                    cx,
                                     arg,
                                     param,
                                     !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()),
@@ -381,7 +383,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
                         assert_eq!(kind, "lifetime");
                         let (provided_arg, param) =
                             force_infer_lt.expect("lifetimes ought to have been inferred");
-                        generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
+                        generic_arg_mismatch_err(cx, provided_arg, param, false, None);
                     }
 
                     break;
@@ -405,7 +407,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
 /// Checks that the correct number of generic arguments have been provided.
 /// Used specifically for function calls.
 pub fn check_generic_arg_count_for_call(
-    tcx: TyCtxt<'_>,
+    cx: &dyn HirTyLowerer<'_>,
     def_id: DefId,
     generics: &ty::Generics,
     seg: &hir::PathSegment<'_>,
@@ -416,14 +418,14 @@ pub fn check_generic_arg_count_for_call(
         IsMethodCall::No => GenericArgPosition::Value,
     };
     let has_self = generics.parent.is_none() && generics.has_self;
-    check_generic_arg_count(tcx, def_id, seg, generics, gen_pos, has_self)
+    check_generic_arg_count(cx, def_id, seg, generics, gen_pos, has_self)
 }
 
 /// Checks that the correct number of generic arguments have been provided.
 /// This is used both for datatypes and function calls.
-#[instrument(skip(tcx, gen_pos), level = "debug")]
+#[instrument(skip(cx, gen_pos), level = "debug")]
 pub(crate) fn check_generic_arg_count(
-    tcx: TyCtxt<'_>,
+    cx: &dyn HirTyLowerer<'_>,
     def_id: DefId,
     seg: &hir::PathSegment<'_>,
     gen_params: &ty::Generics,
@@ -456,11 +458,11 @@ pub(crate) fn check_generic_arg_count(
     if gen_pos != GenericArgPosition::Type
         && let Some(c) = gen_args.constraints.first()
     {
-        prohibit_assoc_item_constraint(tcx, c, None);
+        prohibit_assoc_item_constraint(cx, c, None);
     }
 
     let explicit_late_bound =
-        prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
+        prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos);
 
     let mut invalid_args = vec![];
 
@@ -486,17 +488,15 @@ pub(crate) fn check_generic_arg_count(
             GenericArgsInfo::MissingLifetimes { num_missing_args }
         };
 
-        let reported = WrongNumberOfGenericArgs::new(
-            tcx,
+        let reported = cx.dcx().emit_err(WrongNumberOfGenericArgs::new(
+            cx.tcx(),
             gen_args_info,
             seg,
             gen_params,
             has_self as usize,
             gen_args,
             def_id,
-        )
-        .diagnostic()
-        .emit();
+        ));
 
         Err(reported)
     };
@@ -573,17 +573,17 @@ pub(crate) fn check_generic_arg_count(
         debug!(?gen_args_info);
 
         let reported = gen_args.has_err().unwrap_or_else(|| {
-            WrongNumberOfGenericArgs::new(
-                tcx,
-                gen_args_info,
-                seg,
-                gen_params,
-                params_offset,
-                gen_args,
-                def_id,
-            )
-            .diagnostic()
-            .emit_unless(all_params_are_binded)
+            cx.dcx()
+                .create_err(WrongNumberOfGenericArgs::new(
+                    cx.tcx(),
+                    gen_args_info,
+                    seg,
+                    gen_params,
+                    params_offset,
+                    gen_args,
+                    def_id,
+                ))
+                .emit_unless(all_params_are_binded)
         });
 
         Err(reported)
@@ -623,7 +623,7 @@ pub(crate) fn check_generic_arg_count(
 /// Prohibits explicit lifetime arguments if late-bound lifetime parameters
 /// are present. This is used both for datatypes and function calls.
 pub(crate) fn prohibit_explicit_late_bound_lifetimes(
-    tcx: TyCtxt<'_>,
+    cx: &dyn HirTyLowerer<'_>,
     def: &ty::Generics,
     args: &hir::GenericArgs<'_>,
     position: GenericArgPosition,
@@ -644,13 +644,13 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
         if position == GenericArgPosition::Value
             && args.num_lifetime_params() != param_counts.lifetimes
         {
-            struct_span_code_err!(tcx.dcx(), span, E0794, "{}", msg)
+            struct_span_code_err!(cx.dcx(), span, E0794, "{}", msg)
                 .with_span_note(span_late, note)
                 .emit();
         } else {
             let mut multispan = MultiSpan::from_span(span);
             multispan.push_span_label(span_late, note);
-            tcx.node_span_lint(
+            cx.tcx().node_span_lint(
                 LATE_BOUND_LIFETIME_ARGUMENTS,
                 args.args[0].hir_id(),
                 multispan,
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 240a749de96..29c71c3fa50 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -4,7 +4,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
 use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
+use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
 
 use super::HirTyLowerer;
 
@@ -60,7 +60,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             let msg = "trait objects must include the `dyn` keyword";
             let label = "add `dyn` keyword before this trait";
             let mut diag =
-                rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
+                rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg);
             if self_ty.span.can_be_used_for_suggestions()
                 && !self.maybe_suggest_impl_trait(self_ty, &mut diag)
             {
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 2a68d3915bb..a665306f2c6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -28,7 +28,8 @@ use crate::require_c_abi_if_c_variadic;
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
+    codes::*, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed,
+    FatalError,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -47,8 +48,9 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, Span, DUMMY_SP};
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
@@ -101,6 +103,8 @@ pub enum RegionInferReason<'a> {
 pub trait HirTyLowerer<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx>;
 
+    fn dcx(&self) -> DiagCtxtHandle<'_>;
+
     /// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered.
     fn item_def_id(&self) -> LocalDefId;
 
@@ -176,12 +180,6 @@ pub trait HirTyLowerer<'tcx> {
     /// The inference context of the lowering context if applicable.
     fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
 
-    /// Taint the context with errors.
-    ///
-    /// Invoke this when you encounter an error from some prior pass like name resolution.
-    /// This is used to help suppress derived errors typeck might otherwise report.
-    fn set_tainted_by_errors(&self, e: ErrorGuaranteed);
-
     /// Convenience method for coercing the lowering context into a trait object type.
     ///
     /// Most lowering routines are defined on the trait object type directly
@@ -322,7 +320,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             ty::BoundConstness::NotConst,
         );
         if let Some(c) = item_segment.args().constraints.first() {
-            prohibit_assoc_item_constraint(self.tcx(), c, Some((def_id, item_segment, span)));
+            prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span)));
         }
         args
     }
@@ -393,7 +391,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
 
         let mut arg_count = check_generic_arg_count(
-            tcx,
+            self,
             def_id,
             segment,
             generics,
@@ -401,10 +399,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             self_ty.is_some(),
         );
 
-        if let Err(err) = &arg_count.correct {
-            self.set_tainted_by_errors(err.reported);
-        }
-
         // Skip processing if type has no generic parameters.
         // Traits always have `Self` as a generic parameter, which means they will not return early
         // here and so associated item constraints will be handled regardless of whether there are
@@ -559,13 +553,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
         if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
             && generics.has_self
-            && !tcx.has_attr(def_id, sym::const_trait)
+            && !tcx.is_const_trait(def_id)
         {
-            let reported = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
+            let reported = self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
                 span,
                 modifier: constness.as_str(),
             });
-            self.set_tainted_by_errors(reported);
             arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] });
         }
 
@@ -578,7 +571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             incorrect_args: &arg_count.correct,
         };
         let args = lower_generic_args(
-            tcx,
+            self,
             def_id,
             parent_args,
             self_ty.is_some(),
@@ -608,7 +601,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             ty::BoundConstness::NotConst,
         );
         if let Some(c) = item_segment.args().constraints.first() {
-            prohibit_assoc_item_constraint(self.tcx(), c, Some((item_def_id, item_segment, span)));
+            prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span)));
         }
         args
     }
@@ -714,7 +707,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // would not be well-formed!
             if polarity != ty::PredicatePolarity::Positive {
                 assert!(
-                    self.tcx().dcx().has_errors().is_some(),
+                    self.dcx().has_errors().is_some(),
                     "negative trait bounds should not have assoc item constraints",
                 );
                 continue;
@@ -760,11 +753,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             constness,
         );
         if let Some(c) = trait_segment.args().constraints.first() {
-            prohibit_assoc_item_constraint(
-                self.tcx(),
-                c,
-                Some((trait_def_id, trait_segment, span)),
-            );
+            prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span)));
         }
         ty::TraitRef::new_from_args(self.tcx(), trait_def_id, generic_args)
     }
@@ -876,7 +865,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 span,
                 constraint,
             );
-            self.set_tainted_by_errors(reported);
             return Err(reported);
         };
         debug!(?bound);
@@ -886,7 +874,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             let assoc_kind_str = assoc_kind_str(assoc_kind);
             let ty_param_name = &ty_param_name.to_string();
-            let mut err = tcx.dcx().create_err(crate::errors::AmbiguousAssocItem {
+            let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
                 span,
                 assoc_kind: assoc_kind_str,
                 assoc_name,
@@ -959,7 +947,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 ));
             }
             let reported = err.emit();
-            self.set_tainted_by_errors(reported);
             if !where_bounds.is_empty() {
                 return Err(reported);
             }
@@ -1058,7 +1045,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // trait reference.
                 let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
                     // A cycle error occurred, most likely.
-                    tcx.dcx().span_bug(span, "expected cycle error");
+                    self.dcx().span_bug(span, "expected cycle error");
                 };
 
                 self.probe_single_bound_for_assoc_item(
@@ -1088,10 +1075,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let reported = if variant_resolution.is_some() {
                     // Variant in type position
                     let msg = format!("expected type, found variant `{assoc_ident}`");
-                    tcx.dcx().span_err(span, msg)
+                    self.dcx().span_err(span, msg)
                 } else if qself_ty.is_enum() {
                     let mut err = struct_span_code_err!(
-                        tcx.dcx(),
+                        self.dcx(),
                         assoc_ident.span,
                         E0599,
                         "no variant named `{}` found for enum `{}`",
@@ -1132,7 +1119,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
                     // `<impl Trait as OtherTrait>::Assoc` makes no sense.
                     struct_span_code_err!(
-                        tcx.dcx(),
+                        self.dcx(),
                         tcx.def_span(alias_ty.def_id),
                         E0667,
                         "`impl Trait` is not allowed in path parameters"
@@ -1152,7 +1139,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         assoc_ident.name,
                     )
                 };
-                self.set_tainted_by_errors(reported);
                 return Err(reported);
             }
         };
@@ -1403,13 +1389,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let tcx = self.tcx();
 
         if !tcx.visibility(item_def_id).is_accessible_from(scope, tcx) {
-            let reported = tcx.dcx().emit_err(crate::errors::AssocItemIsPrivate {
+            self.dcx().emit_err(crate::errors::AssocItemIsPrivate {
                 span,
                 kind: tcx.def_descr(item_def_id),
                 name: ident,
                 defined_here_label: tcx.def_span(item_def_id),
             });
-            self.set_tainted_by_errors(reported);
         }
 
         tcx.check_stability(item_def_id, Some(block), span, None);
@@ -1563,7 +1548,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
             if let Some(c) = segment.args().constraints.first() {
-                return Err(prohibit_assoc_item_constraint(self.tcx(), c, None));
+                return Err(prohibit_assoc_item_constraint(self, c, None));
             }
         }
 
@@ -1823,7 +1808,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // `AlwaysApplicable` impl needs a `T: ?Sized` bound for
                 // this to compile if we were to normalize here.
                 if forbid_generic && ty.has_param() {
-                    let mut err = tcx.dcx().struct_span_err(
+                    let mut err = self.dcx().struct_span_err(
                         path.span,
                         "generic `Self` types are currently not permitted in anonymous constants",
                     );
@@ -1835,7 +1820,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         err.span_note(impl_.self_ty.span, "not a concrete type");
                     }
                     let reported = err.emit();
-                    self.set_tainted_by_errors(reported);
                     Ty::new_error(tcx, reported)
                 } else {
                     ty
@@ -1847,19 +1831,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     path.segments[..path.segments.len() - 2].iter(),
                     GenericsArgsErrExtend::None,
                 );
-                // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
-                let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
-                    ty::BoundConstness::ConstIfConst
-                } else {
-                    ty::BoundConstness::NotConst
-                };
                 self.lower_qpath(
                     span,
                     opt_self_ty,
                     def_id,
                     &path.segments[path.segments.len() - 2],
                     path.segments.last().unwrap(),
-                    constness,
+                    ty::BoundConstness::NotConst,
                 )
             }
             Res::PrimTy(prim_ty) => {
@@ -1882,7 +1860,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     .tcx()
                     .dcx()
                     .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted");
-                self.set_tainted_by_errors(e);
                 Ty::new_error(self.tcx(), e)
             }
             Res::Def(..) => {
@@ -1893,7 +1870,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 );
                 Ty::new_error(
                     self.tcx(),
-                    self.tcx().dcx().span_delayed_bug(span, "incorrect resolution for `Self`"),
+                    self.dcx().span_delayed_bug(span, "incorrect resolution for `Self`"),
                 )
             }
             _ => span_bug!(span, "unexpected resolution: {:?}", path.res),
@@ -1966,7 +1943,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let sig_span = self.tcx().def_span(sig_id);
         let mut try_emit = |descr| {
             if emit {
-                self.tcx().dcx().emit_err(crate::errors::NotSupportedDelegation {
+                self.dcx().emit_err(crate::errors::NotSupportedDelegation {
                     span,
                     descr,
                     callee_span: sig_span,
@@ -2016,8 +1993,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ) -> Ty<'tcx> {
         if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output)
         {
-            let e = self.tcx().dcx().span_delayed_bug(span, "not supported delegation case");
-            self.set_tainted_by_errors(e);
+            let e = self.dcx().span_delayed_bug(span, "not supported delegation case");
             return Ty::new_error(self.tcx(), e);
         };
         let sig = self.tcx().fn_sig(sig_id);
@@ -2182,7 +2158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let ty = self.lower_ty(ty);
                 let pat_ty = match pat.kind {
                     hir::PatKind::Wild => {
-                        let err = tcx.dcx().emit_err(WildPatTy { span: pat.span });
+                        let err = self.dcx().emit_err(WildPatTy { span: pat.span });
                         Ty::new_error(tcx, err)
                     }
                     hir::PatKind::Range(start, end, include_end) => {
@@ -2362,7 +2338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| {
             struct_span_code_err!(
-                tcx.dcx(),
+                self.dcx(),
                 decl.output.span(),
                 E0581,
                 "return type references {}, which is not constrained by the fn input types",
@@ -2413,11 +2389,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     }
 
     #[instrument(level = "trace", skip(self, generate_err))]
-    fn validate_late_bound_regions(
-        &self,
+    fn validate_late_bound_regions<'cx>(
+        &'cx self,
         constrained_regions: FxHashSet<ty::BoundRegionKind>,
         referenced_regions: FxHashSet<ty::BoundRegionKind>,
-        generate_err: impl Fn(&str) -> Diag<'tcx>,
+        generate_err: impl Fn(&str) -> Diag<'cx>,
     ) {
         for br in referenced_regions.difference(&constrained_regions) {
             let br_name = match *br {
@@ -2442,7 +2418,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 err.note("consider introducing a named lifetime parameter");
             }
 
-            self.set_tainted_by_errors(err.emit());
+            err.emit();
         }
     }
 
@@ -2483,7 +2459,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // error.
         let r = derived_region_bounds[0];
         if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
-            self.set_tainted_by_errors(tcx.dcx().emit_err(AmbiguousLifetimeBound { span }));
+            self.dcx().emit_err(AmbiguousLifetimeBound { span });
         }
         Some(r)
     }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
index df69c1938dd..aafadc7f9cb 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{DynKind, Upcast};
 use rustc_span::{ErrorGuaranteed, Span};
-use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
+use rustc_trait_selection::error_reporting::traits::report_object_safety_error;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
 
 use smallvec::{smallvec, SmallVec};
@@ -236,7 +236,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             Ty::new_misc_error(tcx).into()
                         } else if arg.walk().any(|arg| arg == dummy_self.into()) {
                             references_self = true;
-                            let guar = tcx.dcx().span_delayed_bug(
+                            let guar = self.dcx().span_delayed_bug(
                                 span,
                                 "trait object trait bounds reference `Self`",
                             );
@@ -262,8 +262,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
                 if references_self {
                     let def_id = i.bottom().0.def_id();
-                    let reported = struct_span_code_err!(
-                        tcx.dcx(),
+                    struct_span_code_err!(
+                        self.dcx(),
                         i.bottom().1,
                         E0038,
                         "the {} `{}` cannot be made into an object",
@@ -275,7 +275,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             .error_msg(),
                     )
                     .emit();
-                    self.set_tainted_by_errors(reported);
                 }
 
                 ty::ExistentialTraitRef { def_id: trait_ref.def_id, args }
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 f3ce3ab6655..5b8b6e98125 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
@@ -78,7 +78,7 @@ use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use rustc_span::{ErrorGuaranteed, Span};
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt};
 
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 44f1830a3b1..dd7fbba753b 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -71,6 +71,7 @@ This API is completely unstable and subject to change.
 #![feature(rustdoc_internals)]
 #![feature(slice_partition_dedup)]
 #![feature(try_blocks)]
+#![feature(unwrap_infallible)]
 // tidy-alphabetical-end
 
 #[macro_use]
@@ -91,7 +92,6 @@ mod errors;
 pub mod hir_wf_check;
 mod impl_wf_check;
 mod outlives;
-pub mod structured_errors;
 mod variance;
 
 use rustc_hir as hir;
diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index 5086c2af3f6..08015c28a26 100644
--- a/compiler/rustc_hir_analysis/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -1,9 +1,9 @@
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_middle::ty::{self, Region, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
+use rustc_type_ir::outlives::{push_outlives_components, Component};
 use smallvec::smallvec;
 
 /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
diff --git a/compiler/rustc_hir_analysis/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs
deleted file mode 100644
index 5abfd25dd95..00000000000
--- a/compiler/rustc_hir_analysis/src/structured_errors.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-mod missing_cast_for_variadic_arg;
-mod sized_unsized_cast;
-mod wrong_number_of_generic_args;
-
-pub use self::{
-    missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*,
-};
-
-use rustc_errors::{Diag, ErrCode};
-use rustc_session::Session;
-
-pub trait StructuredDiag<'tcx> {
-    fn session(&self) -> &Session;
-
-    fn code(&self) -> ErrCode;
-
-    fn diagnostic(&self) -> Diag<'tcx> {
-        let err = self.diagnostic_common();
-
-        if self.session().teach(self.code()) {
-            self.diagnostic_extended(err)
-        } else {
-            self.diagnostic_regular(err)
-        }
-    }
-
-    fn diagnostic_common(&self) -> Diag<'tcx>;
-
-    fn diagnostic_regular(&self, err: Diag<'tcx>) -> Diag<'tcx> {
-        err
-    }
-
-    fn diagnostic_extended(&self, err: Diag<'tcx>) -> Diag<'tcx> {
-        err
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
deleted file mode 100644
index 0e78acbeae2..00000000000
--- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use crate::{errors, structured_errors::StructuredDiag};
-use rustc_errors::{codes::*, Diag};
-use rustc_middle::ty::{Ty, TypeVisitableExt};
-use rustc_session::Session;
-use rustc_span::Span;
-
-pub struct MissingCastForVariadicArg<'tcx, 's> {
-    pub sess: &'tcx Session,
-    pub span: Span,
-    pub ty: Ty<'tcx>,
-    pub cast_ty: &'s str,
-}
-
-impl<'tcx> StructuredDiag<'tcx> for MissingCastForVariadicArg<'tcx, '_> {
-    fn session(&self) -> &Session {
-        self.sess
-    }
-
-    fn code(&self) -> ErrCode {
-        E0617
-    }
-
-    fn diagnostic_common(&self) -> Diag<'tcx> {
-        let (sugg_span, replace, help) =
-            if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) {
-                (Some(self.span), format!("{} as {}", snippet, self.cast_ty), None)
-            } else {
-                (None, "".to_string(), Some(()))
-            };
-
-        let mut err = self.sess.dcx().create_err(errors::PassToVariadicFunction {
-            span: self.span,
-            ty: self.ty,
-            cast_ty: self.cast_ty,
-            help,
-            replace,
-            sugg_span,
-        });
-
-        if self.ty.references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
-        err
-    }
-
-    fn diagnostic_extended(&self, mut err: Diag<'tcx>) -> Diag<'tcx> {
-        err.note(format!(
-            "certain types, like `{}`, must be casted before passing them to a \
-                variadic function, because of arcane ABI rules dictated by the C \
-                standard",
-            self.ty
-        ));
-
-        err
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
deleted file mode 100644
index 9e871ff9af0..00000000000
--- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use crate::{errors, structured_errors::StructuredDiag};
-use rustc_errors::{codes::*, Diag};
-use rustc_middle::ty::{Ty, TypeVisitableExt};
-use rustc_session::Session;
-use rustc_span::Span;
-
-pub struct SizedUnsizedCast<'tcx> {
-    pub sess: &'tcx Session,
-    pub span: Span,
-    pub expr_ty: Ty<'tcx>,
-    pub cast_ty: String,
-}
-
-impl<'tcx> StructuredDiag<'tcx> for SizedUnsizedCast<'tcx> {
-    fn session(&self) -> &Session {
-        self.sess
-    }
-
-    fn code(&self) -> ErrCode {
-        E0607
-    }
-
-    fn diagnostic_common(&self) -> Diag<'tcx> {
-        let mut err = self.sess.dcx().create_err(errors::CastThinPointerToFatPointer {
-            span: self.span,
-            expr_ty: self.expr_ty,
-            cast_ty: self.cast_ty.to_owned(),
-        });
-
-        if self.expr_ty.references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
-        err
-    }
-
-    fn diagnostic_extended(&self, mut err: Diag<'tcx>) -> Diag<'tcx> {
-        err.help(
-            "Thin pointers are \"simple\" pointers: they are purely a reference to a
-memory address.
-
-Fat pointers are pointers referencing \"Dynamically Sized Types\" (also
-called DST). DST don't have a statically known size, therefore they can
-only exist behind some kind of pointers that contain additional
-information. Slices and trait objects are DSTs. In the case of slices,
-the additional information the fat pointer holds is their size.
-
-To fix this error, don't try to cast directly between thin and fat
-pointers.
-
-For more information about casts, take a look at The Book:
-https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions",
-        );
-        err
-    }
-}
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index d6f3f4d640b..39d430cf73b 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -23,6 +23,22 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
 
 hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop`
 
+hir_typeck_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
+    .teach_help = Thin pointers are "simple" pointers: they are purely a reference to a
+        memory address.
+
+        Fat pointers are pointers referencing "Dynamically Sized Types" (also
+        called DST). DST don't have a statically known size, therefore they can
+        only exist behind some kind of pointers that contain additional
+        information. Slices and trait objects are DSTs. In the case of slices,
+        the additional information the fat pointer holds is their size.
+
+        To fix this error, don't try to cast directly between thin and fat
+        pointers.
+
+        For more information about casts, take a look at The Book:
+        https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions",
+
 hir_typeck_cast_unknown_pointer = cannot cast {$to ->
     [true] to
     *[false] from
@@ -123,6 +139,16 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte
 hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
 hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
 
+hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function
+    .suggestion = cast the value to `{$cast_ty}`
+    .help = cast the value to `{$cast_ty}`
+    .teach_help = certain types, like `{$ty}`, must be casted before passing them to a variadic function, because of arcane ABI rules dictated by the C standard
+
+hir_typeck_ptr_cast_add_auto_to_object = adding {$traits_len ->
+    [1] an auto trait {$traits}
+    *[other] auto traits {$traits}
+} to a trait object in a pointer cast may cause UB later on
+
 hir_typeck_remove_semi_for_coerce = you might have meant to return the `match` expression
 hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression
 hir_typeck_remove_semi_for_coerce_ret = the `match` arms can conform to this return type
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 3b199b7e3c2..0d2a55a9507 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -24,8 +24,8 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
+use rustc_trait_selection::error_reporting::traits::DefIdOrName;
 use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 use std::{iter, slice};
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index cb1a412d17e..341d533492d 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -32,9 +32,9 @@ use super::FnCtxt;
 
 use crate::errors;
 use crate::type_error_struct;
-use hir::ExprKind;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed};
-use rustc_hir as hir;
+use rustc_hir::{self as hir, ExprKind};
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
 use rustc_middle::mir::Mutability;
@@ -44,7 +44,7 @@ use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef};
 use rustc_session::lint;
-use rustc_span::def_id::{DefId, LOCAL_CRATE};
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_span::DUMMY_SP;
@@ -73,7 +73,7 @@ enum PointerKind<'tcx> {
     /// No metadata attached, ie pointer to sized type or foreign type
     Thin,
     /// A trait object
-    VTable(Option<DefId>),
+    VTable(&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>),
     /// Slice
     Length,
     /// The unsize info of this projection or opaque type
@@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         Ok(match *t.kind() {
             ty::Slice(_) | ty::Str => Some(PointerKind::Length),
-            ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())),
+            ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),
             ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
                 None => Some(PointerKind::Thin),
                 Some(f) => {
@@ -500,16 +500,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 err.emit();
             }
             CastError::SizedUnsizedCast => {
-                use rustc_hir_analysis::structured_errors::{SizedUnsizedCast, StructuredDiag};
-
-                SizedUnsizedCast {
-                    sess: fcx.tcx.sess,
+                fcx.dcx().emit_err(errors::CastThinPointerToFatPointer {
                     span: self.span,
                     expr_ty: self.expr_ty,
                     cast_ty: fcx.ty_to_string(self.cast_ty),
-                }
-                .diagnostic()
-                .emit();
+                    teach: fcx.tcx.sess.teach(E0607).then_some(()),
+                });
             }
             CastError::IntToFatCast(known_metadata) => {
                 let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
@@ -759,7 +755,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 Err(CastError::IllegalCast)
             }
 
-            // ptr -> *
+            // ptr -> ptr
             (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
 
             // ptr-addr-cast
@@ -803,40 +799,126 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     fn check_ptr_ptr_cast(
         &self,
         fcx: &FnCtxt<'a, 'tcx>,
-        m_expr: ty::TypeAndMut<'tcx>,
-        m_cast: ty::TypeAndMut<'tcx>,
+        m_src: ty::TypeAndMut<'tcx>,
+        m_dst: ty::TypeAndMut<'tcx>,
     ) -> Result<CastKind, CastError> {
-        debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
+        debug!("check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}");
         // ptr-ptr cast. vtables must match.
 
-        let expr_kind = fcx.pointer_kind(m_expr.ty, self.span)?;
-        let cast_kind = fcx.pointer_kind(m_cast.ty, self.span)?;
+        let src_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_src.ty, self.span)?);
+        let dst_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_dst.ty, self.span)?);
 
-        let Some(cast_kind) = cast_kind else {
+        match (src_kind, dst_kind) {
             // We can't cast if target pointer kind is unknown
-            return Err(CastError::UnknownCastPtrKind);
-        };
+            (_, None) => Err(CastError::UnknownCastPtrKind),
+            // Cast to thin pointer is OK
+            (_, Some(PointerKind::Thin)) => Ok(CastKind::PtrPtrCast),
 
-        // Cast to thin pointer is OK
-        if cast_kind == PointerKind::Thin {
-            return Ok(CastKind::PtrPtrCast);
-        }
-
-        let Some(expr_kind) = expr_kind else {
             // We can't cast to fat pointer if source pointer kind is unknown
-            return Err(CastError::UnknownExprPtrKind);
-        };
+            (None, _) => Err(CastError::UnknownExprPtrKind),
+
+            // thin -> fat? report invalid cast (don't complain about vtable kinds)
+            (Some(PointerKind::Thin), _) => Err(CastError::SizedUnsizedCast),
+
+            // trait object -> trait object? need to do additional checks
+            (Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => {
+                match (src_tty.principal(), dst_tty.principal()) {
+                    // A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure
+                    // - `Src` and `Dst` traits are the same
+                    // - traits have the same generic arguments
+                    // - `SrcAuto` is a superset of `DstAuto`
+                    (Some(src_principal), Some(dst_principal)) => {
+                        let tcx = fcx.tcx;
+
+                        // Check that the traits are actually the same.
+                        // The `dyn Src = dyn Dst` check below would suffice,
+                        // but this may produce a better diagnostic.
+                        //
+                        // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
+                        // and is unaffected by this check.
+                        if src_principal.def_id() != dst_principal.def_id() {
+                            return Err(CastError::DifferingKinds);
+                        }
 
-        // thin -> fat? report invalid cast (don't complain about vtable kinds)
-        if expr_kind == PointerKind::Thin {
-            return Err(CastError::SizedUnsizedCast);
-        }
+                        // We need to reconstruct trait object types.
+                        // `m_src` and `m_dst` won't work for us here because they will potentially
+                        // contain wrappers, which we do not care about.
+                        //
+                        // e.g. we want to allow `dyn T -> (dyn T,)`, etc.
+                        //
+                        // We also need to skip auto traits to emit an FCW and not an error.
+                        let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(
+                            tcx.mk_poly_existential_predicates(
+                                &src_tty.without_auto_traits().collect::<Vec<_>>(),
+                            ),
+                            tcx.lifetimes.re_erased,
+                            ty::Dyn,
+                        ));
+                        let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(
+                            tcx.mk_poly_existential_predicates(
+                                &dst_tty.without_auto_traits().collect::<Vec<_>>(),
+                            ),
+                            tcx.lifetimes.re_erased,
+                            ty::Dyn,
+                        ));
 
-        // vtable kinds must match
-        if fcx.tcx.erase_regions(cast_kind) == fcx.tcx.erase_regions(expr_kind) {
-            Ok(CastKind::PtrPtrCast)
-        } else {
-            Err(CastError::DifferingKinds)
+                        // `dyn Src = dyn Dst`, this checks for matching traits/generics
+                        fcx.demand_eqtype(self.span, src_obj, dst_obj);
+
+                        // Check that `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`.
+                        // Emit an FCW otherwise.
+                        let src_auto: FxHashSet<_> = src_tty
+                            .auto_traits()
+                            .chain(
+                                tcx.supertrait_def_ids(src_principal.def_id())
+                                    .filter(|def_id| tcx.trait_is_auto(*def_id)),
+                            )
+                            .collect();
+
+                        let added = dst_tty
+                            .auto_traits()
+                            .filter(|trait_did| !src_auto.contains(trait_did))
+                            .collect::<Vec<_>>();
+
+                        if !added.is_empty() {
+                            tcx.emit_node_span_lint(
+                                lint::builtin::PTR_CAST_ADD_AUTO_TO_OBJECT,
+                                self.expr.hir_id,
+                                self.span,
+                                errors::PtrCastAddAutoToObject {
+                                    traits_len: added.len(),
+                                    traits: {
+                                        let mut traits: Vec<_> = added
+                                            .into_iter()
+                                            .map(|trait_did| tcx.def_path_str(trait_did))
+                                            .collect();
+
+                                        traits.sort();
+                                        traits.into()
+                                    },
+                                },
+                            )
+                        }
+
+                        Ok(CastKind::PtrPtrCast)
+                    }
+
+                    // dyn Auto -> dyn Auto'? ok.
+                    (None, None) => Ok(CastKind::PtrPtrCast),
+
+                    // dyn Trait -> dyn Auto? should be ok, but we used to not allow it.
+                    // FIXME: allow this
+                    (Some(_), None) => Err(CastError::DifferingKinds),
+
+                    // dyn Auto -> dyn Trait? not ok.
+                    (None, Some(_)) => Err(CastError::DifferingKinds),
+                }
+            }
+
+            // fat -> fat? metadata kinds must match
+            (Some(src_kind), Some(dst_kind)) if src_kind == dst_kind => Ok(CastKind::PtrPtrCast),
+
+            (_, _) => Err(CastError::DifferingKinds),
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index ac7ed3e26f9..08de871f6fa 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -17,9 +17,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::error_reporting::traits::ArgKind;
+use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _;
 use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::error_reporting::ArgKind;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_type_ir::ClosureKind;
 use std::iter;
 use std::ops::ControlFlow;
@@ -424,9 +424,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let Some(trait_def_id) = trait_def_id {
                 let found_kind = match closure_kind {
                     hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
-                    hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
-                        self.tcx.async_fn_trait_kind_from_def_id(trait_def_id)
-                    }
+                    hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self
+                        .tcx
+                        .async_fn_trait_kind_from_def_id(trait_def_id)
+                        .or_else(|| self.tcx.fn_trait_kind_from_def_id(trait_def_id)),
                     _ => None,
                 };
 
@@ -470,14 +471,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // for closures and async closures, respectively.
         match closure_kind {
             hir::ClosureKind::Closure
-                if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() => {}
+                if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() =>
+            {
+                self.extract_sig_from_projection(cause_span, projection)
+            }
+            hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async)
+                if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() =>
+            {
+                self.extract_sig_from_projection(cause_span, projection)
+            }
+            // It's possible we've passed the closure to a (somewhat out-of-fashion)
+            // `F: FnOnce() -> Fut, Fut: Future<Output = T>` style bound. Let's still
+            // guide inference here, since it's beneficial for the user.
             hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async)
-                if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() => {}
-            _ => return None,
+                if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() =>
+            {
+                self.extract_sig_from_projection_and_future_bound(cause_span, projection)
+            }
+            _ => None,
         }
+    }
+
+    /// Given an `FnOnce::Output` or `AsyncFn::Output` projection, extract the args
+    /// and return type to infer a [`ty::PolyFnSig`] for the closure.
+    fn extract_sig_from_projection(
+        &self,
+        cause_span: Option<Span>,
+        projection: ty::PolyProjectionPredicate<'tcx>,
+    ) -> Option<ExpectedSig<'tcx>> {
+        let projection = self.resolve_vars_if_possible(projection);
 
         let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1);
-        let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
         debug!(?arg_param_ty);
 
         let ty::Tuple(input_tys) = *arg_param_ty.kind() else {
@@ -486,7 +510,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Since this is a return parameter type it is safe to unwrap.
         let ret_param_ty = projection.skip_binder().term.expect_type();
-        let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
         debug!(?ret_param_ty);
 
         let sig = projection.rebind(self.tcx.mk_fn_sig(
@@ -500,6 +523,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         Some(ExpectedSig { cause_span, sig })
     }
 
+    /// When an async closure is passed to a function that has a "two-part" `Fn`
+    /// and `Future` trait bound, like:
+    ///
+    /// ```rust
+    /// use std::future::Future;
+    ///
+    /// fn not_exactly_an_async_closure<F, Fut>(_f: F)
+    /// where
+    ///     F: FnOnce(String, u32) -> Fut,
+    ///     Fut: Future<Output = i32>,
+    /// {}
+    /// ```
+    ///
+    /// The we want to be able to extract the signature to guide inference in the async
+    /// closure. We will have two projection predicates registered in this case. First,
+    /// we identify the `FnOnce<Args, Output = ?Fut>` bound, and if the output type is
+    /// an inference variable `?Fut`, we check if that is bounded by a `Future<Output = Ty>`
+    /// projection.
+    fn extract_sig_from_projection_and_future_bound(
+        &self,
+        cause_span: Option<Span>,
+        projection: ty::PolyProjectionPredicate<'tcx>,
+    ) -> Option<ExpectedSig<'tcx>> {
+        let projection = self.resolve_vars_if_possible(projection);
+
+        let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1);
+        debug!(?arg_param_ty);
+
+        let ty::Tuple(input_tys) = *arg_param_ty.kind() else {
+            return None;
+        };
+
+        // If the return type is a type variable, look for bounds on it.
+        // We could theoretically support other kinds of return types here,
+        // but none of them would be useful, since async closures return
+        // concrete anonymous future types, and their futures are not coerced
+        // into any other type within the body of the async closure.
+        let ty::Infer(ty::TyVar(return_vid)) = *projection.skip_binder().term.expect_type().kind()
+        else {
+            return None;
+        };
+
+        // FIXME: We may want to elaborate here, though I assume this will be exceedingly rare.
+        for bound in self.obligations_for_self_ty(return_vid) {
+            if let Some(ret_projection) = bound.predicate.as_projection_clause()
+                && let Some(ret_projection) = ret_projection.no_bound_vars()
+                && self.tcx.is_lang_item(ret_projection.def_id(), LangItem::FutureOutput)
+            {
+                let sig = projection.rebind(self.tcx.mk_fn_sig(
+                    input_tys,
+                    ret_projection.term.expect_type(),
+                    false,
+                    hir::Safety::Safe,
+                    Abi::Rust,
+                ));
+
+                return Some(ExpectedSig { cause_span, sig });
+            }
+        }
+
+        None
+    }
+
     fn sig_of_closure(
         &self,
         expr_def_id: LocalDefId,
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index f72e8a4afde..5e2a68e1f02 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -58,9 +58,9 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, DesugaringKind, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtSelectionErrExt as _;
 use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
     self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt,
@@ -1752,10 +1752,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             fcx.probe(|_| {
                 let ocx = ObligationCtxt::new(fcx);
                 ocx.register_obligations(
-                    fcx.tcx
-                        .item_super_predicates(rpit_def_id)
-                        .instantiate_identity_iter()
-                        .filter_map(|clause| {
+                    fcx.tcx.item_super_predicates(rpit_def_id).iter_identity().filter_map(
+                        |clause| {
                             let predicate = clause
                                 .kind()
                                 .map_bound(|clause| match clause {
@@ -1776,7 +1774,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                                 fcx.param_env,
                                 predicate,
                             ))
-                        }),
+                        },
+                    ),
                 );
                 ocx.select_where_possible().is_empty()
             })
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index ad9c1e28211..4f1c2fdd922 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -13,6 +13,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AssocItem, Ty, TypeFoldable, TypeVisitableExt};
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::ObligationCause;
 
 use super::method::probe;
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 98add86252c..9a38d6d4a71 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -4,8 +4,8 @@ use std::borrow::Cow;
 
 use crate::fluent_generated as fluent;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagArgValue, EmissionGuarantee, IntoDiagArg, MultiSpan,
-    SubdiagMessageOp, Subdiagnostic,
+    codes::*, Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg,
+    MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
@@ -253,6 +253,13 @@ pub struct LossyProvenanceInt2Ptr<'tcx> {
     pub sugg: LossyProvenanceInt2PtrSuggestion,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_ptr_cast_add_auto_to_object)]
+pub struct PtrCastAddAutoToObject {
+    pub traits_len: usize,
+    pub traits: DiagSymbolList<String>,
+}
+
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(hir_typeck_suggestion, applicability = "has-placeholders")]
 pub struct LossyProvenanceInt2PtrSuggestion {
@@ -501,6 +508,7 @@ pub enum SuggestBoxing {
 #[suggestion(
     hir_typeck_suggest_ptr_null_mut,
     applicability = "maybe-incorrect",
+    style = "verbose",
     code = "core::ptr::null_mut()"
 )]
 pub struct SuggestPtrNullMut {
@@ -689,3 +697,30 @@ pub struct ReplaceWithName {
     pub span: Span,
     pub name: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_cast_thin_pointer_to_fat_pointer, code = E0607)]
+pub(crate) struct CastThinPointerToFatPointer<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: String,
+    #[note(hir_typeck_teach_help)]
+    pub(crate) teach: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_pass_to_variadic_function, code = E0617)]
+pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+    pub cast_ty: &'a str,
+    #[suggestion(code = "{replace}", applicability = "machine-applicable")]
+    pub sugg_span: Option<Span>,
+    pub replace: String,
+    #[help]
+    pub help: Option<()>,
+    #[note(hir_typeck_teach_help)]
+    pub(crate) teach: Option<()>,
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 2fbc8a3f146..432489330a6 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -53,9 +53,9 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
+use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
 
@@ -708,7 +708,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // else an error would have been flagged by the
                 // `loops` pass for using break with an expression
                 // where you are not supposed to.
-                assert!(expr_opt.is_none() || self.dcx().has_errors().is_some());
+                assert!(expr_opt.is_none() || self.tainted_by_errors().is_some());
             }
 
             // If we encountered a `break`, then (no surprise) it may be possible to break from the
@@ -2551,10 +2551,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         match *base_ty.peel_refs().kind() {
             ty::Array(_, len) => {
-                self.maybe_suggest_array_indexing(&mut err, expr, base, ident, len);
+                self.maybe_suggest_array_indexing(&mut err, base, ident, len);
             }
             ty::RawPtr(..) => {
-                self.suggest_first_deref_field(&mut err, expr, base, ident);
+                self.suggest_first_deref_field(&mut err, base, ident);
             }
             ty::Param(param_ty) => {
                 err.span_label(ident.span, "unknown field");
@@ -2721,7 +2721,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn maybe_suggest_array_indexing(
         &self,
         err: &mut Diag<'_>,
-        expr: &hir::Expr<'_>,
         base: &hir::Expr<'_>,
         field: Ident,
         len: ty::Const<'tcx>,
@@ -2729,32 +2728,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.span_label(field.span, "unknown field");
         if let (Some(len), Ok(user_index)) =
             (len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::<u64>())
-            && let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span)
         {
             let help = "instead of using tuple indexing, use array indexing";
-            let suggestion = format!("{base}[{field}]");
             let applicability = if len < user_index {
                 Applicability::MachineApplicable
             } else {
                 Applicability::MaybeIncorrect
             };
-            err.span_suggestion(expr.span, help, suggestion, applicability);
+            err.multipart_suggestion(
+                help,
+                vec![
+                    (base.span.between(field.span), "[".to_string()),
+                    (field.span.shrink_to_hi(), "]".to_string()),
+                ],
+                applicability,
+            );
         }
     }
 
-    fn suggest_first_deref_field(
-        &self,
-        err: &mut Diag<'_>,
-        expr: &hir::Expr<'_>,
-        base: &hir::Expr<'_>,
-        field: Ident,
-    ) {
+    fn suggest_first_deref_field(&self, err: &mut Diag<'_>, base: &hir::Expr<'_>, field: Ident) {
         err.span_label(field.span, "unknown field");
-        if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) {
-            let msg = format!("`{base}` is a raw pointer; try dereferencing it");
-            let suggestion = format!("(*{base}).{field}");
-            err.span_suggestion(expr.span, msg, suggestion, Applicability::MaybeIncorrect);
-        }
+        let val = if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span)
+            && base.len() < 20
+        {
+            format!("`{base}`")
+        } else {
+            "the value".to_string()
+        };
+        err.multipart_suggestion(
+            format!("{val} is a raw pointer; try dereferencing it"),
+            vec![
+                (base.span.shrink_to_lo(), "(*".to_string()),
+                (base.span.shrink_to_hi(), ")".to_string()),
+            ],
+            Applicability::MaybeIncorrect,
+        );
     }
 
     fn no_such_field_err(&self, field: Ident, expr_t: Ty<'tcx>, id: HirId) -> Diag<'_> {
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 9a353bfe49d..193dbbbcdf4 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -734,7 +734,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                 // struct; however, when EUV is run during typeck, it
                 // may not. This will generate an error earlier in typeck,
                 // so we can just ignore it.
-                if self.cx.tcx().dcx().has_errors().is_none() {
+                if self.cx.tainted_by_errors().is_ok() {
                     span_bug!(with_expr.span, "with expression doesn't evaluate to a struct");
                 }
             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 5450243417f..ea9567f4e3d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -37,7 +37,7 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 use rustc_target::abi::FieldIdx;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{
     self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt,
 };
@@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // parameter's value explicitly, so we have to do some error-
             // checking here.
             let arg_count =
-                check_generic_arg_count_for_call(tcx, def_id, generics, seg, IsMethodCall::No);
+                check_generic_arg_count_for_call(self, def_id, generics, seg, IsMethodCall::No);
 
             if let ExplicitLateBound::Yes = arg_count.explicit_late_bound {
                 explicit_late_bound = ExplicitLateBound::Yes;
@@ -1375,7 +1375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let args_raw = self_ctor_args.unwrap_or_else(|| {
             lower_generic_args(
-                tcx,
+                self,
                 def_id,
                 &[],
                 has_self,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 430e12ff7b8..ab0f356ce91 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -28,7 +28,6 @@ use rustc_hir::{ExprKind, HirId, Node, QPath};
 use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
 use rustc_hir_analysis::check::potentially_plural_count;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
-use rustc_hir_analysis::structured_errors::StructuredDiag;
 use rustc_index::IndexVec;
 use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
 use rustc_infer::infer::TypeTrace;
@@ -40,6 +39,7 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::Session;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{sym, BytePos, Span, DUMMY_SP};
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
 
 use std::iter;
@@ -405,9 +405,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ty: Ty<'tcx>,
                     cast_ty: &str,
                 ) {
-                    use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg;
+                    let (sugg_span, replace, help) =
+                        if let Ok(snippet) = sess.source_map().span_to_snippet(span) {
+                            (Some(span), format!("{snippet} as {cast_ty}"), None)
+                        } else {
+                            (None, "".to_string(), Some(()))
+                        };
 
-                    MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
+                    sess.dcx().emit_err(errors::PassToVariadicFunction {
+                        span,
+                        ty,
+                        cast_ty,
+                        help,
+                        replace,
+                        sugg_span,
+                        teach: sess.teach(E0617).then_some(()),
+                    });
                 }
 
                 // There are a few types which get autopromoted when passed via varargs
@@ -951,6 +964,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return err.emit();
         }
 
+        // Special case, we found an extra argument is provided, which is very common in practice.
+        // but there is a obviously better removing suggestion compared to the current one,
+        // try to find the argument with Error type, if we removed it all the types will become good,
+        // then we will replace the current suggestion.
+        if let [Error::Extra(provided_idx)] = &errors[..] {
+            let remove_idx_is_perfect = |idx: usize| -> bool {
+                let removed_arg_tys = provided_arg_tys
+                    .iter()
+                    .enumerate()
+                    .filter_map(|(j, arg)| if idx == j { None } else { Some(arg) })
+                    .collect::<IndexVec<ProvidedIdx, _>>();
+                std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all(
+                    |((expected_ty, _), (provided_ty, _))| {
+                        !provided_ty.references_error()
+                            && self.can_coerce(*provided_ty, *expected_ty)
+                    },
+                )
+            };
+
+            if !remove_idx_is_perfect(provided_idx.as_usize()) {
+                if let Some(i) = (0..provided_args.len()).find(|&i| remove_idx_is_perfect(i)) {
+                    errors = vec![Error::Extra(ProvidedIdx::from_usize(i))];
+                }
+            }
+        }
+
         let mut err = if formal_and_expected_inputs.len() == provided_args.len() {
             struct_span_code_err!(
                 self.dcx(),
@@ -1358,7 +1397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Some(format!("provide the argument{}", if plural { "s" } else { "" }))
             }
             SuggestionText::Remove(plural) => {
-                err.multipart_suggestion(
+                err.multipart_suggestion_verbose(
                     format!("remove the extra argument{}", if plural { "s" } else { "" }),
                     suggestions,
                     Applicability::HasPlaceholders,
@@ -1652,7 +1691,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
 
-        // Hide the outer diverging and `has_errors` flags.
+        // Hide the outer diverging flags.
         let old_diverges = self.diverges.replace(Diverges::Maybe);
 
         match stmt.kind {
@@ -2042,7 +2081,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                     if block_num > 1 && found_semi {
                         err.span_suggestion_verbose(
-                            span.shrink_to_lo(),
+                            // use the span of the *whole* expr
+                            self.tcx.hir().span(binding_hir_id).shrink_to_lo(),
                             "you might have meant to return this to infer its type parameters",
                             "return ",
                             Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
index fab7eb7495c..90dd5f73586 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -104,8 +104,6 @@ struct NestedObligationsForSelfTy<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
-    type Result = ();
-
     fn span(&self) -> Span {
         self.root_cause.span
     }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index da68da029b4..b5796fbd48a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -5,7 +5,7 @@ mod checks;
 mod inspect_obligations;
 mod suggestions;
 
-use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
+use rustc_errors::DiagCtxtHandle;
 
 use crate::coercion::DynamicCoerceMany;
 use crate::fallback::DivergingFallbackBehavior;
@@ -217,6 +217,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
         self.tcx
     }
 
+    fn dcx(&self) -> DiagCtxtHandle<'_> {
+        self.root_ctxt.dcx()
+    }
+
     fn item_def_id(&self) -> LocalDefId {
         self.body_id
     }
@@ -338,10 +342,6 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
         Some(&self.infcx)
     }
 
-    fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
-        self.infcx.set_tainted_by_errors(e)
-    }
-
     fn lower_fn_sig(
         &self,
         decl: &rustc_hir::FnDecl<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 8d380caf916..5f897c74482 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -32,10 +32,10 @@ use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, Symbol};
+use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::DefIdOrName;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
-use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -2582,7 +2582,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             (hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr), _, &ty::Ref(_, checked, _))
-                if self.can_sub(self.param_env, checked, expected) =>
+                if self.can_eq(self.param_env, checked, expected) =>
             {
                 let make_sugg = |start: Span, end: BytePos| {
                     // skip `(` for tuples such as `(c) = (&123)`.
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 120e3239d1f..e574fde14fb 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -354,7 +354,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         let generics = self.tcx.generics_of(pick.item.def_id);
 
         let arg_count_correct = check_generic_arg_count_for_call(
-            self.tcx,
+            self.fcx,
             pick.item.def_id,
             generics,
             seg,
@@ -425,7 +425,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         }
 
         let args = lower_generic_args(
-            self.tcx,
+            self.fcx,
             pick.item.def_id,
             parent_args,
             false,
@@ -510,9 +510,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                         .report_mismatched_types(&cause, method_self_ty, self_ty, terr)
                         .emit();
                 } else {
-                    error!("{self_ty} was a subtype of {method_self_ty} but now is not?");
-                    // This must already have errored elsewhere.
-                    self.dcx().has_errors().unwrap();
+                    // This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions
+                    // may run before wfcheck if the function is used in const eval.
+                    self.dcx().span_delayed_bug(
+                        cause.span(),
+                        format!("{self_ty} was a subtype of {method_self_ty} but now is not?"),
+                    );
                 }
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index ff8899ae036..dc1b888374c 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Ident;
-use rustc_span::{sym, Span};
+use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{self, NormalizeExt};
 
@@ -359,7 +359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // FIXME(effects) find a better way to do this
         // Operators don't have generic methods, but making them `#[const_trait]` gives them
         // `const host: bool`.
-        let args = if self.tcx.has_attr(trait_def_id, sym::const_trait) {
+        let args = if self.tcx.is_const_trait(trait_def_id) {
             self.tcx.mk_args_from_iter(
                 args.iter()
                     .chain([self.tcx.expected_host_effect_param_for_body(self.body_id).into()]),
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 63b30d79aba..6a7af5510e0 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -33,6 +33,7 @@ use rustc_span::edit_distance::{
 };
 use rustc_span::symbol::sym;
 use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
+use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
 use rustc_trait_selection::traits::query::method_autoderef::{
@@ -857,7 +858,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 let args = self.fresh_args_for_item(self.span, method.def_id);
                 let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
                 let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
-                self.can_sub(self.param_env, fty.output(), expected)
+                self.can_eq(self.param_env, fty.output(), expected)
             }),
             _ => false,
         }
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index e310730bf9e..425289ce3c5 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -35,9 +35,9 @@ use rustc_span::def_id::DefIdSet;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{edit_distance, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span};
 use rustc_span::{Symbol, DUMMY_SP};
+use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote;
+use rustc_trait_selection::error_reporting::traits::on_unimplemented::TypeErrCtxtExt as _;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
-use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     supertraits, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
@@ -499,7 +499,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
-                // If the shadowed binding has an an itializer expression,
+                // If the shadowed binding has an itializer expression,
                 // use the initializer expression'ty to try to find the method again.
                 // For example like:  `let mut x = Vec::new();`,
                 // `Vec::new()` is the itializer expression.
@@ -968,7 +968,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
 
             // Make sure that, if any traits other than the found ones were involved,
-            // we don't don't report an unimplemented trait.
+            // we don't report an unimplemented trait.
             // We don't want to say that `iter::Cloned` is not an iterator, just
             // because of some non-Clone item being iterated over.
             for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
@@ -2129,7 +2129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let target_ty = self
                 .autoderef(sugg_span, rcvr_ty)
                 .find(|(rcvr_ty, _)| {
-                    DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey }
+                    DeepRejectCtxt::new(self.tcx, TreatParams::ForLookup)
                         .types_may_unify(*rcvr_ty, impl_ty)
                 })
                 .map_or(impl_ty, |(ty, _)| ty)
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 5a11cb7096f..d59b8276d3a 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -18,8 +18,8 @@ use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
+use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt};
 use rustc_type_ir::TyKind::*;
 
@@ -838,8 +838,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     },
                                 ) = ex.kind
                                 {
-                                    err.span_suggestion(
-                                        ex.span,
+                                    let span = if let hir::Node::Expr(parent) =
+                                        self.tcx.parent_hir_node(ex.hir_id)
+                                        && let hir::ExprKind::Cast(..) = parent.kind
+                                    {
+                                        // `-1 as usize` -> `usize::MAX`
+                                        parent.span
+                                    } else {
+                                        ex.span
+                                    };
+                                    err.span_suggestion_verbose(
+                                        span,
                                         format!(
                                             "you may have meant the maximum value of `{actual}`",
                                         ),
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index f932a27e9a2..be526e1c26c 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -19,6 +19,7 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span, DUMMY_SP};
 use rustc_target::abi::FieldIdx;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 use ty::VariantDef;
 
@@ -328,8 +329,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         adjust_mode: AdjustMode,
         max_ref_mutbl: MutblCap,
     ) -> (Ty<'tcx>, ByRef, MutblCap) {
-        if let ByRef::Yes(Mutability::Mut) = def_br {
-            debug_assert!(max_ref_mutbl == MutblCap::Mut);
+        #[cfg(debug_assertions)]
+        if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut {
+            span_bug!(pat.span, "Pattern mutability cap violated!");
         }
         match adjust_mode {
             AdjustMode::Pass => (expected, def_br, max_ref_mutbl),
@@ -437,7 +439,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             });
         }
 
-        if self.tcx.features().ref_pat_eat_one_layer_2024 {
+        let features = self.tcx.features();
+        if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural {
             def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl());
             if def_br == ByRef::Yes(Mutability::Not) {
                 max_ref_mutbl = MutblCap::Not;
@@ -669,7 +672,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Determine the binding mode...
         let bm = match user_bind_annot {
             BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
-                if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
+                if pat.span.at_least_rust_2024()
+                    && (self.tcx.features().ref_pat_eat_one_layer_2024
+                        || self.tcx.features().ref_pat_eat_one_layer_2024_structural)
+                {
                     if !self.tcx.features().mut_ref {
                         feature_err(
                             &self.tcx.sess,
@@ -2123,7 +2129,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         mut expected: Ty<'tcx>,
         mut pat_info: PatInfo<'tcx, '_>,
     ) -> Ty<'tcx> {
-        let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024;
+        let tcx = self.tcx;
+        let features = tcx.features();
+        let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024;
+        let ref_pat_eat_one_layer_2024_structural = features.ref_pat_eat_one_layer_2024_structural;
+
+        let no_ref_mut_behind_and =
+            ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural;
         let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and;
 
         let pat_prefix_span =
@@ -2138,32 +2150,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             pat_info.max_ref_mutbl = MutblCap::Mut;
         }
 
+        expected = self.try_structurally_resolve_type(pat.span, expected);
         if new_match_ergonomics {
             if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
-                // ref pattern consumes inherited reference
-
-                if pat_mutbl > inh_mut {
-                    // Tried to match inherited `ref` with `&mut`, which is an error
-                    let err_msg = "cannot match inherited `&` with `&mut` pattern";
-                    let err = if let Some(span) = pat_prefix_span {
-                        let mut err = self.dcx().struct_span_err(span, err_msg);
-                        err.span_suggestion_verbose(
-                            span,
-                            "replace this `&mut` pattern with `&`",
-                            "&",
-                            Applicability::MachineApplicable,
-                        );
-                        err
+                if !ref_pat_eat_one_layer_2024 && let ty::Ref(_, _, r_mutbl) = *expected.kind() {
+                    // Don't attempt to consume inherited reference
+                    pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl);
+                } else {
+                    // ref pattern attempts to consume inherited reference
+                    if pat_mutbl > inh_mut {
+                        // Tried to match inherited `ref` with `&mut`
+                        if !ref_pat_eat_one_layer_2024_structural {
+                            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();
+
+                            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;
+                        }
                     } else {
-                        self.dcx().struct_span_err(pat.span, err_msg)
-                    };
-                    err.emit();
+                        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;
+                    }
                 }
-
-                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;
             }
         } else {
             // Reset binding mode on old editions
@@ -2178,8 +2207,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
-        let tcx = self.tcx;
-        expected = self.try_structurally_resolve_type(pat.span, expected);
         let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
             Ok(()) => {
                 // `demand::subtype` would be good enough, but using `eqtype` turns
@@ -2191,7 +2218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 debug!("check_pat_ref: expected={:?}", expected);
                 match *expected.kind() {
                     ty::Ref(_, r_ty, r_mutbl)
-                        if (new_match_ergonomics && r_mutbl >= pat_mutbl)
+                        if (no_ref_mut_behind_and && r_mutbl >= pat_mutbl)
                             || r_mutbl == pat_mutbl =>
                     {
                         if no_ref_mut_behind_and && r_mutbl == Mutability::Not {
@@ -2499,7 +2526,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
             && let Some(span) = ti.span
             && let Some(_) = ti.origin_expr
-            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
         {
             let resolved_ty = self.resolve_vars_if_possible(ti.expected);
             let (is_slice_or_array_or_vector, resolved_ty) =
@@ -2510,10 +2536,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
                 {
                     // Slicing won't work here, but `.as_deref()` might (issue #91328).
-                    err.span_suggestion(
-                        span,
+                    err.span_suggestion_verbose(
+                        span.shrink_to_hi(),
                         "consider using `as_deref` here",
-                        format!("{snippet}.as_deref()"),
+                        ".as_deref()",
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -2522,10 +2548,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let is_top_level = current_depth <= 1;
             if is_slice_or_array_or_vector && is_top_level {
-                err.span_suggestion(
-                    span,
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi(),
                     "consider slicing here",
-                    format!("{snippet}[..]"),
+                    "[..]",
                     Applicability::MachineApplicable,
                 );
             }
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index b6e9000ef95..c99e8a7fe8e 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -18,7 +18,7 @@ use rustc_trait_selection::traits::{
 use std::cell::RefCell;
 use std::ops::Deref;
 
-// Data shared between a "typeck root" and its nested bodies,
+/// Data shared between a "typeck root" and its nested bodies,
 /// e.g. closures defined within the function. For example:
 /// ```ignore (illustrative)
 /// fn foo() {
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index aea0114167e..e800c1a97d9 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -18,8 +18,8 @@ use rustc_middle::ty::TypeSuperFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::solve;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 
 use std::mem;
 
@@ -219,28 +219,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
         if let hir::ExprKind::Index(ref base, ref index, _) = e.kind {
             // All valid indexing looks like this; might encounter non-valid indexes at this point.
-            let base_ty = self.typeck_results.expr_ty_adjusted_opt(base);
-            if base_ty.is_none() {
-                // When encountering `return [0][0]` outside of a `fn` body we can encounter a base
-                // that isn't in the type table. We assume more relevant errors have already been
-                // emitted. (#64638)
-                assert!(self.tcx().dcx().has_errors().is_some(), "bad base: `{base:?}`");
-            }
-            if let Some(base_ty) = base_ty
-                && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind()
-            {
-                let index_ty =
-                    self.typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| {
-                        // When encountering `return [0][0]` outside of a `fn` body we would attempt
-                        // to access an nonexistent index. We assume that more relevant errors will
-                        // already have been emitted, so we only gate on this with an ICE if no
-                        // error has been emitted. (#64638)
-                        Ty::new_error_with_message(
-                            self.fcx.tcx,
-                            e.span,
-                            format!("bad index {index:?} for base: `{base:?}`"),
-                        )
-                    });
+            let base_ty = self.typeck_results.expr_ty_adjusted(base);
+            if let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() {
+                let index_ty = self.typeck_results.expr_ty_adjusted(index);
                 if self.is_builtin_index(e, base_ty_inner, index_ty) {
                     // Remove the method call record
                     self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index db6b250467e..b775ae1f5e9 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -1,10 +1,7 @@
 // tidy-alphabetical-start
 #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))]
-#![cfg_attr(
-    feature = "nightly",
-    feature(extend_one, min_specialization, new_uninit, step_trait, test)
-)]
 #![cfg_attr(feature = "nightly", allow(internal_features))]
+#![cfg_attr(feature = "nightly", feature(extend_one, new_uninit, step_trait, test))]
 // tidy-alphabetical-end
 
 pub mod bit_set;
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 88298150a79..b866c8b8433 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -208,6 +208,11 @@ impl<I: Idx, T> IndexVec<I, Option<T>> {
     pub fn remove(&mut self, index: I) -> Option<T> {
         self.get_mut(index)?.take()
     }
+
+    #[inline]
+    pub fn contains(&self, index: I) -> bool {
+        self.get(index).and_then(Option::as_ref).is_some()
+    }
 }
 
 impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
diff --git a/compiler/rustc_index_macros/src/lib.rs b/compiler/rustc_index_macros/src/lib.rs
index 3e55dd82a6e..2b444932f85 100644
--- a/compiler/rustc_index_macros/src/lib.rs
+++ b/compiler/rustc_index_macros/src/lib.rs
@@ -34,10 +34,7 @@ mod newtype;
 ///   optimizations. The default max value is 0xFFFF_FF00.
 /// - `#[gate_rustc_only]`: makes parts of the generated code nightly-only.
 #[proc_macro]
-#[cfg_attr(
-    feature = "nightly",
-    allow_internal_unstable(step_trait, rustc_attrs, trusted_step, min_specialization)
-)]
+#[cfg_attr(feature = "nightly", allow_internal_unstable(step_trait, rustc_attrs, trusted_step))]
 pub fn newtype_index(input: TokenStream) -> TokenStream {
     newtype::newtype(input)
 }
diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs
index 41863f7b15f..1ac2c44e9dc 100644
--- a/compiler/rustc_index_macros/src/newtype.rs
+++ b/compiler/rustc_index_macros/src/newtype.rs
@@ -139,10 +139,6 @@ impl Parse for Newtype {
                         Self::index(start).checked_sub(u).map(Self::from_usize)
                     }
                 }
-
-                // Safety: The implementation of `Step` upholds all invariants.
-                #gate_rustc_only
-                unsafe impl ::std::iter::TrustedStep for #name {}
             }
         } else {
             quote! {}
diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml
index c1565a7d40f..1f616710200 100644
--- a/compiler/rustc_infer/Cargo.toml
+++ b/compiler/rustc_infer/Cargo.toml
@@ -16,8 +16,10 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
+rustc_next_trait_solver = { path = "../rustc_next_trait_solver" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
new file mode 100644
index 00000000000..f35a8162d96
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -0,0 +1,176 @@
+///! Definition of `InferCtxtLike` from the librarified type layer.
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode};
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::DUMMY_SP;
+use rustc_type_ir::relate::Relate;
+use rustc_type_ir::InferCtxtLike;
+
+use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin};
+
+impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
+    type Interner = TyCtxt<'tcx>;
+
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn solver_mode(&self) -> ty::solve::SolverMode {
+        match self.intercrate {
+            true => SolverMode::Coherence,
+            false => SolverMode::Normal,
+        }
+    }
+
+    fn universe(&self) -> ty::UniverseIndex {
+        self.universe()
+    }
+
+    fn create_next_universe(&self) -> ty::UniverseIndex {
+        self.create_next_universe()
+    }
+
+    fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> {
+        match self.probe_ty_var(vid) {
+            Err(universe) => Some(universe),
+            Ok(_) => None,
+        }
+    }
+
+    fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
+        match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
+            Err(universe) => Some(universe),
+            Ok(_) => None,
+        }
+    }
+
+    fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> {
+        match self.probe_const_var(ct) {
+            Err(universe) => Some(universe),
+            Ok(_) => None,
+        }
+    }
+
+    fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
+        self.root_var(var)
+    }
+
+    fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
+        self.root_const_var(var)
+    }
+
+    fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> {
+        match self.probe_ty_var(vid) {
+            Ok(ty) => ty,
+            Err(_) => Ty::new_var(self.tcx, self.root_var(vid)),
+        }
+    }
+
+    fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
+        self.opportunistic_resolve_int_var(vid)
+    }
+
+    fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
+        self.opportunistic_resolve_float_var(vid)
+    }
+
+    fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> {
+        match self.probe_const_var(vid) {
+            Ok(ct) => ct,
+            Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)),
+        }
+    }
+
+    fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> {
+        match self.probe_effect_var(vid) {
+            Some(ct) => ct,
+            None => {
+                ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(self.root_effect_var(vid)))
+            }
+        }
+    }
+
+    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
+        self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
+    }
+
+    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
+        self.defining_opaque_types()
+    }
+
+    fn next_ty_infer(&self) -> Ty<'tcx> {
+        self.next_ty_var(DUMMY_SP)
+    }
+
+    fn next_const_infer(&self) -> ty::Const<'tcx> {
+        self.next_const_var(DUMMY_SP)
+    }
+
+    fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
+        self.fresh_args_for_item(DUMMY_SP, def_id)
+    }
+
+    fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
+        &self,
+        value: ty::Binder<'tcx, T>,
+    ) -> T {
+        self.instantiate_binder_with_fresh_vars(
+            DUMMY_SP,
+            BoundRegionConversionTime::HigherRankedType,
+            value,
+        )
+    }
+
+    fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
+        &self,
+        value: ty::Binder<'tcx, T>,
+        f: impl FnOnce(T) -> U,
+    ) -> U {
+        self.enter_forall(value, f)
+    }
+
+    fn relate<T: Relate<TyCtxt<'tcx>>>(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: T,
+        variance: ty::Variance,
+        rhs: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
+        self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
+    }
+
+    fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: T,
+        rhs: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
+        self.at(&ObligationCause::dummy(), param_env)
+            .eq_structurally_relating_aliases_no_trace(lhs, rhs)
+    }
+
+    fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.shallow_resolve(ty)
+    }
+
+    fn resolve_vars_if_possible<T>(&self, value: T) -> T
+    where
+        T: TypeFoldable<TyCtxt<'tcx>>,
+    {
+        self.resolve_vars_if_possible(value)
+    }
+
+    fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
+        self.probe(|_| probe())
+    }
+
+    fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
+        self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup)
+    }
+
+    fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
+        self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy());
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index a8fd3ca8c59..bb1285ee813 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -45,13 +45,10 @@
 //! ported to this system, and which relies on string concatenation at the
 //! time of error detection.
 
-use super::lexical_region_resolve::RegionResolutionError;
-use super::region_constraints::GenericKind;
-use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
+use super::{InferCtxt, TypeTrace, ValuePairs};
 
-use crate::errors::{self, ObligationCauseFailureCode, TypeErrorAdditionalDiags};
+use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags};
 use crate::infer;
-use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
 use crate::infer::ExpectedFound;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -61,38 +58,36 @@ use crate::traits::{
 use crate::infer::relate::{self, RelateResult, TypeRelation};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{
-    codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxtHandle,
-    DiagStyledString, ErrorGuaranteed, IntoDiagArg, StringPart,
+    pluralize, Applicability, Diag, DiagCtxtHandle, DiagStyledString, IntoDiagArg, StringPart,
 };
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{self as hir, ParamName};
+use rustc_hir::{self as hir};
 use rustc_macros::extension;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::DepContext;
 use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _};
-use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{
-    self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    TypeVisitable, TypeVisitableExt,
 };
-use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::borrow::Cow;
 use std::ops::{ControlFlow, Deref};
 use std::path::PathBuf;
 use std::{cmp, fmt, iter};
 
-mod note;
 mod note_and_explain;
 mod suggest;
 
 pub(crate) mod need_type_info;
 pub mod sub_relations;
 pub use need_type_info::TypeAnnotationNeeded;
+pub mod region;
 
 pub mod nice_region_error;
 
@@ -159,245 +154,6 @@ impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> {
     }
 }
 
-pub(super) fn note_and_explain_region<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    err: &mut Diag<'_>,
-    generic_param_scope: LocalDefId,
-    prefix: &str,
-    region: ty::Region<'tcx>,
-    suffix: &str,
-    alt_span: Option<Span>,
-) {
-    let (description, span) = match *region {
-        ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => {
-            msg_span_from_named_region(tcx, generic_param_scope, region, alt_span)
-        }
-
-        ty::ReError(_) => return,
-
-        // FIXME(#125431): `ReVar` shouldn't reach here.
-        ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span),
-
-        ty::ReBound(..) | ty::ReErased => {
-            bug!("unexpected region for note_and_explain_region: {:?}", region);
-        }
-    };
-
-    emit_msg_span(err, prefix, description, span, suffix);
-}
-
-fn explain_free_region<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    err: &mut Diag<'_>,
-    generic_param_scope: LocalDefId,
-    prefix: &str,
-    region: ty::Region<'tcx>,
-    suffix: &str,
-) {
-    let (description, span) = msg_span_from_named_region(tcx, generic_param_scope, region, None);
-
-    label_msg_span(err, prefix, description, span, suffix);
-}
-
-fn msg_span_from_named_region<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    generic_param_scope: LocalDefId,
-    region: ty::Region<'tcx>,
-    alt_span: Option<Span>,
-) -> (String, Option<Span>) {
-    match *region {
-        ty::ReEarlyParam(br) => {
-            let scope = tcx
-                .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
-                .expect_local();
-            let span = if let Some(param) =
-                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
-            {
-                param.span
-            } else {
-                tcx.def_span(scope)
-            };
-            let text = if br.has_name() {
-                format!("the lifetime `{}` as defined here", br.name)
-            } else {
-                "the anonymous lifetime as defined here".to_string()
-            };
-            (text, Some(span))
-        }
-        ty::ReLateParam(ref fr) => {
-            if !fr.bound_region.is_named()
-                && let Some((ty, _)) =
-                    find_anon_type(tcx, generic_param_scope, region, &fr.bound_region)
-            {
-                ("the anonymous lifetime defined here".to_string(), Some(ty.span))
-            } else {
-                match fr.bound_region {
-                    ty::BoundRegionKind::BrNamed(_, name) => {
-                        let span = if let Some(param) = tcx
-                            .hir()
-                            .get_generics(generic_param_scope)
-                            .and_then(|generics| generics.get_named(name))
-                        {
-                            param.span
-                        } else {
-                            tcx.def_span(generic_param_scope)
-                        };
-                        let text = if name == kw::UnderscoreLifetime {
-                            "the anonymous lifetime as defined here".to_string()
-                        } else {
-                            format!("the lifetime `{name}` as defined here")
-                        };
-                        (text, Some(span))
-                    }
-                    ty::BrAnon => (
-                        "the anonymous lifetime as defined here".to_string(),
-                        Some(tcx.def_span(generic_param_scope)),
-                    ),
-                    _ => (
-                        format!("the lifetime `{region}` as defined here"),
-                        Some(tcx.def_span(generic_param_scope)),
-                    ),
-                }
-            }
-        }
-        ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
-        ty::RePlaceholder(ty::PlaceholderRegion {
-            bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, name), .. },
-            ..
-        }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
-        ty::RePlaceholder(ty::PlaceholderRegion {
-            bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon, .. },
-            ..
-        }) => ("an anonymous lifetime".to_owned(), None),
-        _ => bug!("{:?}", region),
-    }
-}
-
-fn emit_msg_span(
-    err: &mut Diag<'_>,
-    prefix: &str,
-    description: String,
-    span: Option<Span>,
-    suffix: &str,
-) {
-    let message = format!("{prefix}{description}{suffix}");
-
-    if let Some(span) = span {
-        err.span_note(span, message);
-    } else {
-        err.note(message);
-    }
-}
-
-fn label_msg_span(
-    err: &mut Diag<'_>,
-    prefix: &str,
-    description: String,
-    span: Option<Span>,
-    suffix: &str,
-) {
-    let message = format!("{prefix}{description}{suffix}");
-
-    if let Some(span) = span {
-        err.span_label(span, message);
-    } else {
-        err.note(message);
-    }
-}
-
-#[instrument(level = "trace", skip(infcx))]
-pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
-    infcx: &'a InferCtxt<'tcx>,
-    generic_param_scope: LocalDefId,
-    span: Span,
-    hidden_ty: Ty<'tcx>,
-    hidden_region: ty::Region<'tcx>,
-    opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
-) -> Diag<'a> {
-    let tcx = infcx.tcx;
-    let mut err = infcx.dcx().create_err(errors::OpaqueCapturesLifetime {
-        span,
-        opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args),
-        opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
-    });
-
-    // Explain the region we are capturing.
-    match *hidden_region {
-        ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
-            // Assuming regionck succeeded (*), we ought to always be
-            // capturing *some* region from the fn header, and hence it
-            // ought to be free. So under normal circumstances, we will go
-            // down this path which gives a decent human readable
-            // explanation.
-            //
-            // (*) if not, the `tainted_by_errors` field would be set to
-            // `Some(ErrorGuaranteed)` in any case, so we wouldn't be here at all.
-            explain_free_region(
-                tcx,
-                &mut err,
-                generic_param_scope,
-                &format!("hidden type `{hidden_ty}` captures "),
-                hidden_region,
-                "",
-            );
-            if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
-                let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
-                nice_region_error::suggest_new_region_bound(
-                    tcx,
-                    &mut err,
-                    fn_returns,
-                    hidden_region.to_string(),
-                    None,
-                    format!("captures `{hidden_region}`"),
-                    None,
-                    Some(reg_info.def_id),
-                )
-            }
-        }
-        ty::RePlaceholder(_) => {
-            explain_free_region(
-                tcx,
-                &mut err,
-                generic_param_scope,
-                &format!("hidden type `{}` captures ", hidden_ty),
-                hidden_region,
-                "",
-            );
-        }
-        ty::ReError(_) => {
-            err.downgrade_to_delayed_bug();
-        }
-        _ => {
-            // Ugh. This is a painful case: the hidden region is not one
-            // that we can easily summarize or explain. This can happen
-            // in a case like
-            // `tests/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`:
-            //
-            // ```
-            // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> {
-            //   if condition() { a } else { b }
-            // }
-            // ```
-            //
-            // Here the captured lifetime is the intersection of `'a` and
-            // `'b`, which we can't quite express.
-
-            // We can at least report a really cryptic error for now.
-            note_and_explain_region(
-                tcx,
-                &mut err,
-                generic_param_scope,
-                &format!("hidden type `{hidden_ty}` captures "),
-                hidden_region,
-                "",
-                None,
-            );
-        }
-    }
-
-    err
-}
-
 impl<'tcx> InferCtxt<'tcx> {
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let (def_id, args) = match *ty.kind() {
@@ -438,193 +194,6 @@ impl<'tcx> InferCtxt<'tcx> {
 }
 
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    pub fn report_region_errors(
-        &self,
-        generic_param_scope: LocalDefId,
-        errors: &[RegionResolutionError<'tcx>],
-    ) -> ErrorGuaranteed {
-        assert!(!errors.is_empty());
-
-        if let Some(guaranteed) = self.infcx.tainted_by_errors() {
-            return guaranteed;
-        }
-
-        debug!("report_region_errors(): {} errors to start", errors.len());
-
-        // try to pre-process the errors, which will group some of them
-        // together into a `ProcessedErrors` group:
-        let errors = self.process_errors(errors);
-
-        debug!("report_region_errors: {} errors after preprocessing", errors.len());
-
-        let mut guar = None;
-        for error in errors {
-            debug!("report_region_errors: error = {:?}", error);
-
-            let e = if let Some(guar) =
-                self.try_report_nice_region_error(generic_param_scope, &error)
-            {
-                guar
-            } else {
-                match error.clone() {
-                    // These errors could indicate all manner of different
-                    // problems with many different solutions. Rather
-                    // than generate a "one size fits all" error, what we
-                    // attempt to do is go through a number of specific
-                    // scenarios and try to find the best way to present
-                    // the error. If all of these fails, we fall back to a rather
-                    // general bit of code that displays the error information
-                    RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
-                        if sub.is_placeholder() || sup.is_placeholder() {
-                            self.report_placeholder_failure(generic_param_scope, origin, sub, sup)
-                                .emit()
-                        } else {
-                            self.report_concrete_failure(generic_param_scope, origin, sub, sup)
-                                .emit()
-                        }
-                    }
-
-                    RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => self
-                        .report_generic_bound_failure(
-                            generic_param_scope,
-                            origin.span(),
-                            Some(origin),
-                            param_ty,
-                            sub,
-                        ),
-
-                    RegionResolutionError::SubSupConflict(
-                        _,
-                        var_origin,
-                        sub_origin,
-                        sub_r,
-                        sup_origin,
-                        sup_r,
-                        _,
-                    ) => {
-                        if sub_r.is_placeholder() {
-                            self.report_placeholder_failure(
-                                generic_param_scope,
-                                sub_origin,
-                                sub_r,
-                                sup_r,
-                            )
-                            .emit()
-                        } else if sup_r.is_placeholder() {
-                            self.report_placeholder_failure(
-                                generic_param_scope,
-                                sup_origin,
-                                sub_r,
-                                sup_r,
-                            )
-                            .emit()
-                        } else {
-                            self.report_sub_sup_conflict(
-                                generic_param_scope,
-                                var_origin,
-                                sub_origin,
-                                sub_r,
-                                sup_origin,
-                                sup_r,
-                            )
-                        }
-                    }
-
-                    RegionResolutionError::UpperBoundUniverseConflict(
-                        _,
-                        _,
-                        _,
-                        sup_origin,
-                        sup_r,
-                    ) => {
-                        assert!(sup_r.is_placeholder());
-
-                        // Make a dummy value for the "sub region" --
-                        // this is the initial value of the
-                        // placeholder. In practice, we expect more
-                        // tailored errors that don't really use this
-                        // value.
-                        let sub_r = self.tcx.lifetimes.re_erased;
-
-                        self.report_placeholder_failure(
-                            generic_param_scope,
-                            sup_origin,
-                            sub_r,
-                            sup_r,
-                        )
-                        .emit()
-                    }
-
-                    RegionResolutionError::CannotNormalize(clause, origin) => {
-                        let clause: ty::Clause<'tcx> =
-                            clause.map_bound(ty::ClauseKind::TypeOutlives).upcast(self.tcx);
-                        self.tcx
-                            .dcx()
-                            .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
-                            .emit()
-                    }
-                }
-            };
-
-            guar = Some(e)
-        }
-
-        guar.unwrap()
-    }
-
-    // This method goes through all the errors and try to group certain types
-    // of error together, for the purpose of suggesting explicit lifetime
-    // parameters to the user. This is done so that we can have a more
-    // complete view of what lifetimes should be the same.
-    // If the return value is an empty vector, it means that processing
-    // failed (so the return value of this method should not be used).
-    //
-    // The method also attempts to weed out messages that seem like
-    // duplicates that will be unhelpful to the end-user. But
-    // obviously it never weeds out ALL errors.
-    fn process_errors(
-        &self,
-        errors: &[RegionResolutionError<'tcx>],
-    ) -> Vec<RegionResolutionError<'tcx>> {
-        debug!("process_errors()");
-
-        // We want to avoid reporting generic-bound failures if we can
-        // avoid it: these have a very high rate of being unhelpful in
-        // practice. This is because they are basically secondary
-        // checks that test the state of the region graph after the
-        // rest of inference is done, and the other kinds of errors
-        // indicate that the region constraint graph is internally
-        // inconsistent, so these test results are likely to be
-        // meaningless.
-        //
-        // Therefore, we filter them out of the list unless they are
-        // the only thing in the list.
-
-        let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
-            RegionResolutionError::GenericBoundFailure(..) => true,
-            RegionResolutionError::ConcreteFailure(..)
-            | RegionResolutionError::SubSupConflict(..)
-            | RegionResolutionError::UpperBoundUniverseConflict(..)
-            | RegionResolutionError::CannotNormalize(..) => false,
-        };
-
-        let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
-            errors.to_owned()
-        } else {
-            errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
-        };
-
-        // sort the errors by span, for better error message stability.
-        errors.sort_by_key(|u| match *u {
-            RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
-            RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
-            RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
-            RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
-            RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(),
-        });
-        errors
-    }
-
     /// Adds a note if the types come from similarly named crates
     fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) {
         use hir::def_id::CrateNum;
@@ -1168,14 +737,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let output1 = sig1.output();
         let output2 = sig2.output();
         let (x1, x2) = self.cmp(output1, output2);
-        if !output1.is_unit() {
+        let output_diff = x1 != x2;
+        if !output1.is_unit() || output_diff {
             values.0.push_normal(" -> ");
             (values.0).0.extend(x1.0);
         }
-        if !output2.is_unit() {
+        if !output2.is_unit() || output_diff {
             values.1.push_normal(" -> ");
             (values.1).0.extend(x2.0);
         }
+
         values
     }
 
@@ -2339,359 +1910,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         ))
     }
 
-    pub fn report_generic_bound_failure(
-        &self,
-        generic_param_scope: LocalDefId,
-        span: Span,
-        origin: Option<SubregionOrigin<'tcx>>,
-        bound_kind: GenericKind<'tcx>,
-        sub: Region<'tcx>,
-    ) -> ErrorGuaranteed {
-        self.construct_generic_bound_failure(generic_param_scope, span, origin, bound_kind, sub)
-            .emit()
-    }
-
-    pub fn construct_generic_bound_failure(
-        &self,
-        generic_param_scope: LocalDefId,
-        span: Span,
-        origin: Option<SubregionOrigin<'tcx>>,
-        bound_kind: GenericKind<'tcx>,
-        sub: Region<'tcx>,
-    ) -> Diag<'a> {
-        if let Some(SubregionOrigin::CompareImplItemObligation {
-            span,
-            impl_item_def_id,
-            trait_item_def_id,
-        }) = origin
-        {
-            return self.infcx.report_extra_impl_obligation(
-                span,
-                impl_item_def_id,
-                trait_item_def_id,
-                &format!("`{bound_kind}: {sub}`"),
-            );
-        }
-
-        let labeled_user_string = match bound_kind {
-            GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
-            GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
-            GenericKind::Alias(ref p) => match p.kind(self.tcx) {
-                ty::Projection | ty::Inherent => {
-                    format!("the associated type `{p}`")
-                }
-                ty::Weak => format!("the type alias `{p}`"),
-                ty::Opaque => format!("the opaque type `{p}`"),
-            },
-        };
-
-        let mut err = self
-            .tcx
-            .dcx()
-            .struct_span_err(span, format!("{labeled_user_string} may not live long enough"));
-        err.code(match sub.kind() {
-            ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309,
-            ty::ReStatic => E0310,
-            _ => E0311,
-        });
-
-        '_explain: {
-            let (description, span) = match sub.kind() {
-                ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
-                    msg_span_from_named_region(self.tcx, generic_param_scope, sub, Some(span))
-                }
-                _ => (format!("lifetime `{sub}`"), Some(span)),
-            };
-            let prefix = format!("{labeled_user_string} must be valid for ");
-            label_msg_span(&mut err, &prefix, description, span, "...");
-            if let Some(origin) = origin {
-                self.note_region_origin(&mut err, &origin);
-            }
-        }
-
-        'suggestion: {
-            let msg = "consider adding an explicit lifetime bound";
-
-            if (bound_kind, sub).has_infer_regions()
-                || (bound_kind, sub).has_placeholders()
-                || !bound_kind.is_suggestable(self.tcx, false)
-            {
-                let lt_name = sub.get_name_or_anon().to_string();
-                err.help(format!("{msg} `{bound_kind}: {lt_name}`..."));
-                break 'suggestion;
-            }
-
-            let mut generic_param_scope = generic_param_scope;
-            while self.tcx.def_kind(generic_param_scope) == DefKind::OpaqueTy {
-                generic_param_scope = self.tcx.local_parent(generic_param_scope);
-            }
-
-            // type_param_sugg_span is (span, has_bounds, needs_parentheses)
-            let (type_scope, type_param_sugg_span) = match bound_kind {
-                GenericKind::Param(param) => {
-                    let generics = self.tcx.generics_of(generic_param_scope);
-                    let type_param = generics.type_param(param, self.tcx);
-                    let def_id = type_param.def_id.expect_local();
-                    let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id;
-                    // Get the `hir::Param` to verify whether it already has any bounds.
-                    // We do this to avoid suggesting code that ends up as `T: 'a'b`,
-                    // instead we suggest `T: 'a + 'b` in that case.
-                    let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
-                    let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
-                        Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
-                        // If `param` corresponds to `Self`, no usable suggestion span.
-                        None if generics.has_self && param.index == 0 => None,
-                        None => {
-                            let span = if let Some(param) =
-                                hir_generics.params.iter().find(|param| param.def_id == def_id)
-                                && let ParamName::Plain(ident) = param.name
-                            {
-                                ident.span.shrink_to_hi()
-                            } else {
-                                let span = self.tcx.def_span(def_id);
-                                span.shrink_to_hi()
-                            };
-                            Some((span, false, None))
-                        }
-                    };
-                    (scope, sugg_span)
-                }
-                _ => (generic_param_scope, None),
-            };
-            let suggestion_scope = {
-                let lifetime_scope = match sub.kind() {
-                    ty::ReStatic => hir::def_id::CRATE_DEF_ID,
-                    _ => match self.tcx.is_suitable_region(generic_param_scope, sub) {
-                        Some(info) => info.def_id,
-                        None => generic_param_scope,
-                    },
-                };
-                match self.tcx.is_descendant_of(type_scope.into(), lifetime_scope.into()) {
-                    true => type_scope,
-                    false => lifetime_scope,
-                }
-            };
-
-            let mut suggs = vec![];
-            let lt_name = self.suggest_name_region(generic_param_scope, sub, &mut suggs);
-
-            if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span
-                && suggestion_scope == type_scope
-            {
-                let suggestion =
-                    if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
-
-                if let Some(open_paren_sp) = open_paren_sp {
-                    suggs.push((open_paren_sp, "(".to_string()));
-                    suggs.push((sp, format!("){suggestion}")));
-                } else {
-                    suggs.push((sp, suggestion))
-                }
-            } else if let GenericKind::Alias(ref p) = bound_kind
-                && let ty::Projection = p.kind(self.tcx)
-                && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
-                && let Some(ty::ImplTraitInTraitData::Trait { .. }) =
-                    self.tcx.opt_rpitit_info(p.def_id)
-            {
-                // The lifetime found in the `impl` is longer than the one on the RPITIT.
-                // Do not suggest `<Type as Trait>::{opaque}: 'static`.
-            } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
-                let pred = format!("{bound_kind}: {lt_name}");
-                let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
-                suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
-            } else {
-                let consider = format!("{msg} `{bound_kind}: {sub}`...");
-                err.help(consider);
-            }
-
-            if !suggs.is_empty() {
-                err.multipart_suggestion_verbose(
-                    msg,
-                    suggs,
-                    Applicability::MaybeIncorrect, // Issue #41966
-                );
-            }
-        }
-
-        err
-    }
-
-    pub fn suggest_name_region(
-        &self,
-        generic_param_scope: LocalDefId,
-        lifetime: Region<'tcx>,
-        add_lt_suggs: &mut Vec<(Span, String)>,
-    ) -> String {
-        struct LifetimeReplaceVisitor<'tcx, 'a> {
-            tcx: TyCtxt<'tcx>,
-            needle: hir::LifetimeName,
-            new_lt: &'a str,
-            add_lt_suggs: &'a mut Vec<(Span, String)>,
-        }
-
-        impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'tcx, '_> {
-            fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
-                if lt.res == self.needle {
-                    let (pos, span) = lt.suggestion_position();
-                    let new_lt = &self.new_lt;
-                    let sugg = match pos {
-                        hir::LifetimeSuggestionPosition::Normal => format!("{new_lt}"),
-                        hir::LifetimeSuggestionPosition::Ampersand => format!("{new_lt} "),
-                        hir::LifetimeSuggestionPosition::ElidedPath => format!("<{new_lt}>"),
-                        hir::LifetimeSuggestionPosition::ElidedPathArgument => {
-                            format!("{new_lt}, ")
-                        }
-                        hir::LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lt}"),
-                    };
-                    self.add_lt_suggs.push((span, sugg));
-                }
-            }
-
-            fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) {
-                let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind else {
-                    return hir::intravisit::walk_ty(self, ty);
-                };
-                let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty();
-                if let Some(&(_, b)) =
-                    opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle)
-                {
-                    let prev_needle =
-                        std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b));
-                    for bound in opaque_ty.bounds {
-                        self.visit_param_bound(bound);
-                    }
-                    self.needle = prev_needle;
-                }
-            }
-        }
-
-        let (lifetime_def_id, lifetime_scope) =
-            match self.tcx.is_suitable_region(generic_param_scope, lifetime) {
-                Some(info) if !lifetime.has_name() => {
-                    (info.bound_region.get_id().unwrap().expect_local(), info.def_id)
-                }
-                _ => return lifetime.get_name_or_anon().to_string(),
-            };
-
-        let new_lt = {
-            let generics = self.tcx.generics_of(lifetime_scope);
-            let mut used_names =
-                iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
-                    .flat_map(|g| &g.own_params)
-                    .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
-                    .map(|p| p.name)
-                    .collect::<Vec<_>>();
-            let hir_id = self.tcx.local_def_id_to_hir_id(lifetime_scope);
-            // consider late-bound lifetimes ...
-            used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(
-                |p| match p {
-                    ty::BoundVariableKind::Region(lt) => lt.get_name(),
-                    _ => None,
-                },
-            ));
-            (b'a'..=b'z')
-                .map(|c| format!("'{}", c as char))
-                .find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
-                .unwrap_or("'lt".to_string())
-        };
-
-        let mut visitor = LifetimeReplaceVisitor {
-            tcx: self.tcx,
-            needle: hir::LifetimeName::Param(lifetime_def_id),
-            add_lt_suggs,
-            new_lt: &new_lt,
-        };
-        match self.tcx.expect_hir_owner_node(lifetime_scope) {
-            hir::OwnerNode::Item(i) => visitor.visit_item(i),
-            hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i),
-            hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
-            hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i),
-            hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"),
-            hir::OwnerNode::Synthetic => unreachable!(),
-        }
-
-        let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
-        let sugg = ast_generics
-            .span_for_lifetime_suggestion()
-            .map(|span| (span, format!("{new_lt}, ")))
-            .unwrap_or_else(|| (ast_generics.span, format!("<{new_lt}>")));
-        add_lt_suggs.push(sugg);
-
-        new_lt
-    }
-
-    fn report_sub_sup_conflict(
-        &self,
-        generic_param_scope: LocalDefId,
-        var_origin: RegionVariableOrigin,
-        sub_origin: SubregionOrigin<'tcx>,
-        sub_region: Region<'tcx>,
-        sup_origin: SubregionOrigin<'tcx>,
-        sup_region: Region<'tcx>,
-    ) -> ErrorGuaranteed {
-        let mut err = self.report_inference_failure(var_origin);
-
-        note_and_explain_region(
-            self.tcx,
-            &mut err,
-            generic_param_scope,
-            "first, the lifetime cannot outlive ",
-            sup_region,
-            "...",
-            None,
-        );
-
-        debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
-        debug!("report_sub_sup_conflict: sub_region={:?}", sub_region);
-        debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin);
-        debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
-        debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
-
-        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)
-            && let Some((sub_expected, sub_found, _)) = self.values_str(sub_trace.values)
-            && sub_expected == sup_expected
-            && sub_found == sup_found
-        {
-            note_and_explain_region(
-                self.tcx,
-                &mut err,
-                generic_param_scope,
-                "...but the lifetime must also be valid for ",
-                sub_region,
-                "...",
-                None,
-            );
-            err.span_note(
-                sup_trace.cause.span,
-                format!("...so that the {}", sup_trace.cause.as_requirement_str()),
-            );
-
-            err.note_expected_found(&"", sup_expected, &"", sup_found);
-            return if sub_region.is_error() | sup_region.is_error() {
-                err.delay_as_bug()
-            } else {
-                err.emit()
-            };
-        }
-
-        self.note_region_origin(&mut err, &sup_origin);
-
-        note_and_explain_region(
-            self.tcx,
-            &mut err,
-            generic_param_scope,
-            "but, the lifetime must be valid for ",
-            sub_region,
-            "...",
-            None,
-        );
-
-        self.note_region_origin(&mut err, &sub_origin);
-        if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { err.emit() }
-    }
-
     /// Determine whether an error associated with the given span and definition
     /// should be treated as being caused by the implicit `From` conversion
     /// within `?` desugaring.
@@ -2790,55 +2008,6 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> {
     }
 }
 
-impl<'tcx> InferCtxt<'tcx> {
-    fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> {
-        let br_string = |br: ty::BoundRegionKind| {
-            let mut s = match br {
-                ty::BrNamed(_, name) => name.to_string(),
-                _ => String::new(),
-            };
-            if !s.is_empty() {
-                s.push(' ');
-            }
-            s
-        };
-        let var_description = match var_origin {
-            infer::MiscVariable(_) => String::new(),
-            infer::PatternRegion(_) => " for pattern".to_string(),
-            infer::AddrOfRegion(_) => " for borrow expression".to_string(),
-            infer::Autoref(_) => " for autoref".to_string(),
-            infer::Coercion(_) => " for automatic coercion".to_string(),
-            infer::BoundRegion(_, br, infer::FnCall) => {
-                format!(" for lifetime parameter {}in function call", br_string(br))
-            }
-            infer::BoundRegion(_, br, infer::HigherRankedType) => {
-                format!(" for lifetime parameter {}in generic type", br_string(br))
-            }
-            infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
-                " for lifetime parameter {}in trait containing associated type `{}`",
-                br_string(br),
-                self.tcx.associated_item(def_id).name
-            ),
-            infer::RegionParameterDefinition(_, name) => {
-                format!(" for lifetime parameter `{name}`")
-            }
-            infer::UpvarRegion(ref upvar_id, _) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                format!(" for capture of `{var_name}` by closure")
-            }
-            infer::Nll(..) => bug!("NLL variable found in lexical phase"),
-        };
-
-        struct_span_code_err!(
-            self.dcx(),
-            var_origin.span(),
-            E0495,
-            "cannot infer an appropriate lifetime{} due to conflicting requirements",
-            var_description
-        )
-    }
-}
-
 pub enum FailureCode {
     Error0317,
     Error0580,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 71a86683c21..9973646aecd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -534,7 +534,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let tcx = self.tcx();
 
         // Find the method being called.
-        let Ok(Some(instance)) = ty::Instance::resolve(
+        let Ok(Some(instance)) = ty::Instance::try_resolve(
             tcx,
             ctxt.param_env,
             ctxt.assoc_item.def_id,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
deleted file mode 100644
index d1fc9c9f140..00000000000
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ /dev/null
@@ -1,421 +0,0 @@
-use crate::errors::{
-    note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
-    RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
-};
-use crate::fluent_generated as fluent;
-use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
-use crate::infer::{self, SubregionOrigin};
-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::symbol::kw;
-
-use super::ObligationCauseAsDiagArg;
-
-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_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index bc59b5e033b..d5e7de897d0 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -52,10 +52,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         ) = tcx.sess.source_map().span_to_snippet(sp) =>
                     {
                         if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
-                            diag.span_suggestion(
-                                sp,
+                            diag.span_suggestion_verbose(
+                                sp.shrink_to_hi(),
                                 "use a float literal",
-                                format!("{snippet}.0"),
+                                ".0",
                                 MachineApplicable,
                             );
                         }
@@ -820,7 +820,7 @@ fn foo(&self) -> Self::T { String::new() }
                                 tcx.defaultness(item.id.owner_id)
                             {
                                 let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
-                                if self.infcx.can_eq(param_env, assoc_ty, found) {
+                                if self.infcx.can_eq_shallow(param_env, assoc_ty, found) {
                                     diag.span_label(
                                         item.span,
                                         "associated type defaults can't be assumed inside the \
@@ -843,7 +843,7 @@ fn foo(&self) -> Self::T { String::new() }
                         let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
                         if let hir::Defaultness::Default { has_value: true } =
                             tcx.defaultness(item.id.owner_id)
-                            && self.infcx.can_eq(param_env, assoc_ty, found)
+                            && self.infcx.can_eq_shallow(param_env, assoc_ty, found)
                         {
                             diag.span_label(
                                 item.span,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/region.rs b/compiler/rustc_infer/src/infer/error_reporting/region.rs
new file mode 100644
index 00000000000..5a465f46e47
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/error_reporting/region.rs
@@ -0,0 +1,1259 @@
+use std::iter;
+
+use rustc_errors::{
+    struct_span_code_err, Applicability, Diag, Subdiagnostic, E0309, E0310, E0311, E0495,
+};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{self as hir, ParamName};
+use rustc_middle::bug;
+use rustc_middle::traits::ObligationCauseCode;
+use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::{self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _};
+use rustc_span::symbol::kw;
+use rustc_span::{ErrorGuaranteed, Span};
+use rustc_type_ir::Upcast as _;
+
+use super::nice_region_error::find_anon_type;
+use super::{nice_region_error, ObligationCauseAsDiagArg};
+use crate::errors::{
+    self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound,
+    OutlivesContent, RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
+};
+use crate::fluent_generated as fluent;
+use crate::infer::error_reporting::{ObligationCauseExt as _, TypeErrCtxt};
+use crate::infer::region_constraints::GenericKind;
+use crate::infer::{self, InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin};
+
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    pub fn report_region_errors(
+        &self,
+        generic_param_scope: LocalDefId,
+        errors: &[RegionResolutionError<'tcx>],
+    ) -> ErrorGuaranteed {
+        assert!(!errors.is_empty());
+
+        if let Some(guaranteed) = self.infcx.tainted_by_errors() {
+            return guaranteed;
+        }
+
+        debug!("report_region_errors(): {} errors to start", errors.len());
+
+        // try to pre-process the errors, which will group some of them
+        // together into a `ProcessedErrors` group:
+        let errors = self.process_errors(errors);
+
+        debug!("report_region_errors: {} errors after preprocessing", errors.len());
+
+        let mut guar = None;
+        for error in errors {
+            debug!("report_region_errors: error = {:?}", error);
+
+            let e = if let Some(guar) =
+                self.try_report_nice_region_error(generic_param_scope, &error)
+            {
+                guar
+            } else {
+                match error.clone() {
+                    // These errors could indicate all manner of different
+                    // problems with many different solutions. Rather
+                    // than generate a "one size fits all" error, what we
+                    // attempt to do is go through a number of specific
+                    // scenarios and try to find the best way to present
+                    // the error. If all of these fails, we fall back to a rather
+                    // general bit of code that displays the error information
+                    RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
+                        if sub.is_placeholder() || sup.is_placeholder() {
+                            self.report_placeholder_failure(generic_param_scope, origin, sub, sup)
+                                .emit()
+                        } else {
+                            self.report_concrete_failure(generic_param_scope, origin, sub, sup)
+                                .emit()
+                        }
+                    }
+
+                    RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => self
+                        .report_generic_bound_failure(
+                            generic_param_scope,
+                            origin.span(),
+                            Some(origin),
+                            param_ty,
+                            sub,
+                        ),
+
+                    RegionResolutionError::SubSupConflict(
+                        _,
+                        var_origin,
+                        sub_origin,
+                        sub_r,
+                        sup_origin,
+                        sup_r,
+                        _,
+                    ) => {
+                        if sub_r.is_placeholder() {
+                            self.report_placeholder_failure(
+                                generic_param_scope,
+                                sub_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                            .emit()
+                        } else if sup_r.is_placeholder() {
+                            self.report_placeholder_failure(
+                                generic_param_scope,
+                                sup_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                            .emit()
+                        } else {
+                            self.report_sub_sup_conflict(
+                                generic_param_scope,
+                                var_origin,
+                                sub_origin,
+                                sub_r,
+                                sup_origin,
+                                sup_r,
+                            )
+                        }
+                    }
+
+                    RegionResolutionError::UpperBoundUniverseConflict(
+                        _,
+                        _,
+                        _,
+                        sup_origin,
+                        sup_r,
+                    ) => {
+                        assert!(sup_r.is_placeholder());
+
+                        // Make a dummy value for the "sub region" --
+                        // this is the initial value of the
+                        // placeholder. In practice, we expect more
+                        // tailored errors that don't really use this
+                        // value.
+                        let sub_r = self.tcx.lifetimes.re_erased;
+
+                        self.report_placeholder_failure(
+                            generic_param_scope,
+                            sup_origin,
+                            sub_r,
+                            sup_r,
+                        )
+                        .emit()
+                    }
+
+                    RegionResolutionError::CannotNormalize(clause, origin) => {
+                        let clause: ty::Clause<'tcx> =
+                            clause.map_bound(ty::ClauseKind::TypeOutlives).upcast(self.tcx);
+                        self.tcx
+                            .dcx()
+                            .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
+                            .emit()
+                    }
+                }
+            };
+
+            guar = Some(e)
+        }
+
+        guar.unwrap()
+    }
+
+    // This method goes through all the errors and try to group certain types
+    // of error together, for the purpose of suggesting explicit lifetime
+    // parameters to the user. This is done so that we can have a more
+    // complete view of what lifetimes should be the same.
+    // If the return value is an empty vector, it means that processing
+    // failed (so the return value of this method should not be used).
+    //
+    // The method also attempts to weed out messages that seem like
+    // duplicates that will be unhelpful to the end-user. But
+    // obviously it never weeds out ALL errors.
+    fn process_errors(
+        &self,
+        errors: &[RegionResolutionError<'tcx>],
+    ) -> Vec<RegionResolutionError<'tcx>> {
+        debug!("process_errors()");
+
+        // We want to avoid reporting generic-bound failures if we can
+        // avoid it: these have a very high rate of being unhelpful in
+        // practice. This is because they are basically secondary
+        // checks that test the state of the region graph after the
+        // rest of inference is done, and the other kinds of errors
+        // indicate that the region constraint graph is internally
+        // inconsistent, so these test results are likely to be
+        // meaningless.
+        //
+        // Therefore, we filter them out of the list unless they are
+        // the only thing in the list.
+
+        let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
+            RegionResolutionError::GenericBoundFailure(..) => true,
+            RegionResolutionError::ConcreteFailure(..)
+            | RegionResolutionError::SubSupConflict(..)
+            | RegionResolutionError::UpperBoundUniverseConflict(..)
+            | RegionResolutionError::CannotNormalize(..) => false,
+        };
+
+        let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
+            errors.to_owned()
+        } else {
+            errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
+        };
+
+        // sort the errors by span, for better error message stability.
+        errors.sort_by_key(|u| match *u {
+            RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
+            RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
+            RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
+            RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
+            RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(),
+        });
+        errors
+    }
+
+    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,
+                );
+            }
+        }
+    }
+
+    pub fn report_generic_bound_failure(
+        &self,
+        generic_param_scope: LocalDefId,
+        span: Span,
+        origin: Option<SubregionOrigin<'tcx>>,
+        bound_kind: GenericKind<'tcx>,
+        sub: Region<'tcx>,
+    ) -> ErrorGuaranteed {
+        self.construct_generic_bound_failure(generic_param_scope, span, origin, bound_kind, sub)
+            .emit()
+    }
+
+    pub fn construct_generic_bound_failure(
+        &self,
+        generic_param_scope: LocalDefId,
+        span: Span,
+        origin: Option<SubregionOrigin<'tcx>>,
+        bound_kind: GenericKind<'tcx>,
+        sub: Region<'tcx>,
+    ) -> Diag<'a> {
+        if let Some(SubregionOrigin::CompareImplItemObligation {
+            span,
+            impl_item_def_id,
+            trait_item_def_id,
+        }) = origin
+        {
+            return self.infcx.report_extra_impl_obligation(
+                span,
+                impl_item_def_id,
+                trait_item_def_id,
+                &format!("`{bound_kind}: {sub}`"),
+            );
+        }
+
+        let labeled_user_string = match bound_kind {
+            GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
+            GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
+            GenericKind::Alias(ref p) => match p.kind(self.tcx) {
+                ty::Projection | ty::Inherent => {
+                    format!("the associated type `{p}`")
+                }
+                ty::Weak => format!("the type alias `{p}`"),
+                ty::Opaque => format!("the opaque type `{p}`"),
+            },
+        };
+
+        let mut err = self
+            .tcx
+            .dcx()
+            .struct_span_err(span, format!("{labeled_user_string} may not live long enough"));
+        err.code(match sub.kind() {
+            ty::ReEarlyParam(_) | ty::ReLateParam(_) if sub.has_name() => E0309,
+            ty::ReStatic => E0310,
+            _ => E0311,
+        });
+
+        '_explain: {
+            let (description, span) = match sub.kind() {
+                ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
+                    msg_span_from_named_region(self.tcx, generic_param_scope, sub, Some(span))
+                }
+                _ => (format!("lifetime `{sub}`"), Some(span)),
+            };
+            let prefix = format!("{labeled_user_string} must be valid for ");
+            label_msg_span(&mut err, &prefix, description, span, "...");
+            if let Some(origin) = origin {
+                self.note_region_origin(&mut err, &origin);
+            }
+        }
+
+        'suggestion: {
+            let msg = "consider adding an explicit lifetime bound";
+
+            if (bound_kind, sub).has_infer_regions()
+                || (bound_kind, sub).has_placeholders()
+                || !bound_kind.is_suggestable(self.tcx, false)
+            {
+                let lt_name = sub.get_name_or_anon().to_string();
+                err.help(format!("{msg} `{bound_kind}: {lt_name}`..."));
+                break 'suggestion;
+            }
+
+            let mut generic_param_scope = generic_param_scope;
+            while self.tcx.def_kind(generic_param_scope) == DefKind::OpaqueTy {
+                generic_param_scope = self.tcx.local_parent(generic_param_scope);
+            }
+
+            // type_param_sugg_span is (span, has_bounds, needs_parentheses)
+            let (type_scope, type_param_sugg_span) = match bound_kind {
+                GenericKind::Param(param) => {
+                    let generics = self.tcx.generics_of(generic_param_scope);
+                    let type_param = generics.type_param(param, self.tcx);
+                    let def_id = type_param.def_id.expect_local();
+                    let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id;
+                    // Get the `hir::Param` to verify whether it already has any bounds.
+                    // We do this to avoid suggesting code that ends up as `T: 'a'b`,
+                    // instead we suggest `T: 'a + 'b` in that case.
+                    let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
+                    let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
+                        Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
+                        // If `param` corresponds to `Self`, no usable suggestion span.
+                        None if generics.has_self && param.index == 0 => None,
+                        None => {
+                            let span = if let Some(param) =
+                                hir_generics.params.iter().find(|param| param.def_id == def_id)
+                                && let ParamName::Plain(ident) = param.name
+                            {
+                                ident.span.shrink_to_hi()
+                            } else {
+                                let span = self.tcx.def_span(def_id);
+                                span.shrink_to_hi()
+                            };
+                            Some((span, false, None))
+                        }
+                    };
+                    (scope, sugg_span)
+                }
+                _ => (generic_param_scope, None),
+            };
+            let suggestion_scope = {
+                let lifetime_scope = match sub.kind() {
+                    ty::ReStatic => hir::def_id::CRATE_DEF_ID,
+                    _ => match self.tcx.is_suitable_region(generic_param_scope, sub) {
+                        Some(info) => info.def_id,
+                        None => generic_param_scope,
+                    },
+                };
+                match self.tcx.is_descendant_of(type_scope.into(), lifetime_scope.into()) {
+                    true => type_scope,
+                    false => lifetime_scope,
+                }
+            };
+
+            let mut suggs = vec![];
+            let lt_name = self.suggest_name_region(generic_param_scope, sub, &mut suggs);
+
+            if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span
+                && suggestion_scope == type_scope
+            {
+                let suggestion =
+                    if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
+
+                if let Some(open_paren_sp) = open_paren_sp {
+                    suggs.push((open_paren_sp, "(".to_string()));
+                    suggs.push((sp, format!("){suggestion}")));
+                } else {
+                    suggs.push((sp, suggestion))
+                }
+            } else if let GenericKind::Alias(ref p) = bound_kind
+                && let ty::Projection = p.kind(self.tcx)
+                && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
+                && let Some(ty::ImplTraitInTraitData::Trait { .. }) =
+                    self.tcx.opt_rpitit_info(p.def_id)
+            {
+                // The lifetime found in the `impl` is longer than the one on the RPITIT.
+                // Do not suggest `<Type as Trait>::{opaque}: 'static`.
+            } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
+                let pred = format!("{bound_kind}: {lt_name}");
+                let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
+                suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
+            } else {
+                let consider = format!("{msg} `{bound_kind}: {sub}`...");
+                err.help(consider);
+            }
+
+            if !suggs.is_empty() {
+                err.multipart_suggestion_verbose(
+                    msg,
+                    suggs,
+                    Applicability::MaybeIncorrect, // Issue #41966
+                );
+            }
+        }
+
+        err
+    }
+
+    pub fn suggest_name_region(
+        &self,
+        generic_param_scope: LocalDefId,
+        lifetime: Region<'tcx>,
+        add_lt_suggs: &mut Vec<(Span, String)>,
+    ) -> String {
+        struct LifetimeReplaceVisitor<'tcx, 'a> {
+            tcx: TyCtxt<'tcx>,
+            needle: hir::LifetimeName,
+            new_lt: &'a str,
+            add_lt_suggs: &'a mut Vec<(Span, String)>,
+        }
+
+        impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'tcx, '_> {
+            fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
+                if lt.res == self.needle {
+                    let (pos, span) = lt.suggestion_position();
+                    let new_lt = &self.new_lt;
+                    let sugg = match pos {
+                        hir::LifetimeSuggestionPosition::Normal => format!("{new_lt}"),
+                        hir::LifetimeSuggestionPosition::Ampersand => format!("{new_lt} "),
+                        hir::LifetimeSuggestionPosition::ElidedPath => format!("<{new_lt}>"),
+                        hir::LifetimeSuggestionPosition::ElidedPathArgument => {
+                            format!("{new_lt}, ")
+                        }
+                        hir::LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lt}"),
+                    };
+                    self.add_lt_suggs.push((span, sugg));
+                }
+            }
+
+            fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) {
+                let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind else {
+                    return hir::intravisit::walk_ty(self, ty);
+                };
+                let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty();
+                if let Some(&(_, b)) =
+                    opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle)
+                {
+                    let prev_needle =
+                        std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b));
+                    for bound in opaque_ty.bounds {
+                        self.visit_param_bound(bound);
+                    }
+                    self.needle = prev_needle;
+                }
+            }
+        }
+
+        let (lifetime_def_id, lifetime_scope) =
+            match self.tcx.is_suitable_region(generic_param_scope, lifetime) {
+                Some(info) if !lifetime.has_name() => {
+                    (info.bound_region.get_id().unwrap().expect_local(), info.def_id)
+                }
+                _ => return lifetime.get_name_or_anon().to_string(),
+            };
+
+        let new_lt = {
+            let generics = self.tcx.generics_of(lifetime_scope);
+            let mut used_names =
+                iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
+                    .flat_map(|g| &g.own_params)
+                    .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
+                    .map(|p| p.name)
+                    .collect::<Vec<_>>();
+            let hir_id = self.tcx.local_def_id_to_hir_id(lifetime_scope);
+            // consider late-bound lifetimes ...
+            used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(
+                |p| match p {
+                    ty::BoundVariableKind::Region(lt) => lt.get_name(),
+                    _ => None,
+                },
+            ));
+            (b'a'..=b'z')
+                .map(|c| format!("'{}", c as char))
+                .find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
+                .unwrap_or("'lt".to_string())
+        };
+
+        let mut visitor = LifetimeReplaceVisitor {
+            tcx: self.tcx,
+            needle: hir::LifetimeName::Param(lifetime_def_id),
+            add_lt_suggs,
+            new_lt: &new_lt,
+        };
+        match self.tcx.expect_hir_owner_node(lifetime_scope) {
+            hir::OwnerNode::Item(i) => visitor.visit_item(i),
+            hir::OwnerNode::ForeignItem(i) => visitor.visit_foreign_item(i),
+            hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
+            hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i),
+            hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"),
+            hir::OwnerNode::Synthetic => unreachable!(),
+        }
+
+        let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
+        let sugg = ast_generics
+            .span_for_lifetime_suggestion()
+            .map(|span| (span, format!("{new_lt}, ")))
+            .unwrap_or_else(|| (ast_generics.span, format!("<{new_lt}>")));
+        add_lt_suggs.push(sugg);
+
+        new_lt
+    }
+
+    fn report_sub_sup_conflict(
+        &self,
+        generic_param_scope: LocalDefId,
+        var_origin: RegionVariableOrigin,
+        sub_origin: SubregionOrigin<'tcx>,
+        sub_region: Region<'tcx>,
+        sup_origin: SubregionOrigin<'tcx>,
+        sup_region: Region<'tcx>,
+    ) -> ErrorGuaranteed {
+        let mut err = self.report_inference_failure(var_origin);
+
+        note_and_explain_region(
+            self.tcx,
+            &mut err,
+            generic_param_scope,
+            "first, the lifetime cannot outlive ",
+            sup_region,
+            "...",
+            None,
+        );
+
+        debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
+        debug!("report_sub_sup_conflict: sub_region={:?}", sub_region);
+        debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin);
+        debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
+        debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
+
+        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)
+            && let Some((sub_expected, sub_found, _)) = self.values_str(sub_trace.values)
+            && sub_expected == sup_expected
+            && sub_found == sup_found
+        {
+            note_and_explain_region(
+                self.tcx,
+                &mut err,
+                generic_param_scope,
+                "...but the lifetime must also be valid for ",
+                sub_region,
+                "...",
+                None,
+            );
+            err.span_note(
+                sup_trace.cause.span,
+                format!("...so that the {}", sup_trace.cause.as_requirement_str()),
+            );
+
+            err.note_expected_found(&"", sup_expected, &"", sup_found);
+            return if sub_region.is_error() | sup_region.is_error() {
+                err.delay_as_bug()
+            } else {
+                err.emit()
+            };
+        }
+
+        self.note_region_origin(&mut err, &sup_origin);
+
+        note_and_explain_region(
+            self.tcx,
+            &mut err,
+            generic_param_scope,
+            "but, the lifetime must be valid for ",
+            sub_region,
+            "...",
+            None,
+        );
+
+        self.note_region_origin(&mut err, &sub_origin);
+        if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { err.emit() }
+    }
+
+    fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> {
+        let br_string = |br: ty::BoundRegionKind| {
+            let mut s = match br {
+                ty::BrNamed(_, name) => name.to_string(),
+                _ => String::new(),
+            };
+            if !s.is_empty() {
+                s.push(' ');
+            }
+            s
+        };
+        let var_description = match var_origin {
+            infer::MiscVariable(_) => String::new(),
+            infer::PatternRegion(_) => " for pattern".to_string(),
+            infer::AddrOfRegion(_) => " for borrow expression".to_string(),
+            infer::Autoref(_) => " for autoref".to_string(),
+            infer::Coercion(_) => " for automatic coercion".to_string(),
+            infer::BoundRegion(_, br, infer::FnCall) => {
+                format!(" for lifetime parameter {}in function call", br_string(br))
+            }
+            infer::BoundRegion(_, br, infer::HigherRankedType) => {
+                format!(" for lifetime parameter {}in generic type", br_string(br))
+            }
+            infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
+                " for lifetime parameter {}in trait containing associated type `{}`",
+                br_string(br),
+                self.tcx.associated_item(def_id).name
+            ),
+            infer::RegionParameterDefinition(_, name) => {
+                format!(" for lifetime parameter `{name}`")
+            }
+            infer::UpvarRegion(ref upvar_id, _) => {
+                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
+                format!(" for capture of `{var_name}` by closure")
+            }
+            infer::Nll(..) => bug!("NLL variable found in lexical phase"),
+        };
+
+        struct_span_code_err!(
+            self.dcx(),
+            var_origin.span(),
+            E0495,
+            "cannot infer an appropriate lifetime{} due to conflicting requirements",
+            var_description
+        )
+    }
+}
+
+pub(super) fn note_and_explain_region<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    err: &mut Diag<'_>,
+    generic_param_scope: LocalDefId,
+    prefix: &str,
+    region: ty::Region<'tcx>,
+    suffix: &str,
+    alt_span: Option<Span>,
+) {
+    let (description, span) = match *region {
+        ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::RePlaceholder(_) | ty::ReStatic => {
+            msg_span_from_named_region(tcx, generic_param_scope, region, alt_span)
+        }
+
+        ty::ReError(_) => return,
+
+        // FIXME(#125431): `ReVar` shouldn't reach here.
+        ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span),
+
+        ty::ReBound(..) | ty::ReErased => {
+            bug!("unexpected region for note_and_explain_region: {:?}", region);
+        }
+    };
+
+    emit_msg_span(err, prefix, description, span, suffix);
+}
+
+fn explain_free_region<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    err: &mut Diag<'_>,
+    generic_param_scope: LocalDefId,
+    prefix: &str,
+    region: ty::Region<'tcx>,
+    suffix: &str,
+) {
+    let (description, span) = msg_span_from_named_region(tcx, generic_param_scope, region, None);
+
+    label_msg_span(err, prefix, description, span, suffix);
+}
+
+fn msg_span_from_named_region<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
+    region: ty::Region<'tcx>,
+    alt_span: Option<Span>,
+) -> (String, Option<Span>) {
+    match *region {
+        ty::ReEarlyParam(br) => {
+            let scope = tcx
+                .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
+                .expect_local();
+            let span = if let Some(param) =
+                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+            {
+                param.span
+            } else {
+                tcx.def_span(scope)
+            };
+            let text = if br.has_name() {
+                format!("the lifetime `{}` as defined here", br.name)
+            } else {
+                "the anonymous lifetime as defined here".to_string()
+            };
+            (text, Some(span))
+        }
+        ty::ReLateParam(ref fr) => {
+            if !fr.bound_region.is_named()
+                && let Some((ty, _)) =
+                    find_anon_type(tcx, generic_param_scope, region, &fr.bound_region)
+            {
+                ("the anonymous lifetime defined here".to_string(), Some(ty.span))
+            } else {
+                match fr.bound_region {
+                    ty::BoundRegionKind::BrNamed(_, name) => {
+                        let span = if let Some(param) = tcx
+                            .hir()
+                            .get_generics(generic_param_scope)
+                            .and_then(|generics| generics.get_named(name))
+                        {
+                            param.span
+                        } else {
+                            tcx.def_span(generic_param_scope)
+                        };
+                        let text = if name == kw::UnderscoreLifetime {
+                            "the anonymous lifetime as defined here".to_string()
+                        } else {
+                            format!("the lifetime `{name}` as defined here")
+                        };
+                        (text, Some(span))
+                    }
+                    ty::BrAnon => (
+                        "the anonymous lifetime as defined here".to_string(),
+                        Some(tcx.def_span(generic_param_scope)),
+                    ),
+                    _ => (
+                        format!("the lifetime `{region}` as defined here"),
+                        Some(tcx.def_span(generic_param_scope)),
+                    ),
+                }
+            }
+        }
+        ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
+        ty::RePlaceholder(ty::PlaceholderRegion {
+            bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, name), .. },
+            ..
+        }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
+        ty::RePlaceholder(ty::PlaceholderRegion {
+            bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon, .. },
+            ..
+        }) => ("an anonymous lifetime".to_owned(), None),
+        _ => bug!("{:?}", region),
+    }
+}
+
+fn emit_msg_span(
+    err: &mut Diag<'_>,
+    prefix: &str,
+    description: String,
+    span: Option<Span>,
+    suffix: &str,
+) {
+    let message = format!("{prefix}{description}{suffix}");
+
+    if let Some(span) = span {
+        err.span_note(span, message);
+    } else {
+        err.note(message);
+    }
+}
+
+fn label_msg_span(
+    err: &mut Diag<'_>,
+    prefix: &str,
+    description: String,
+    span: Option<Span>,
+    suffix: &str,
+) {
+    let message = format!("{prefix}{description}{suffix}");
+
+    if let Some(span) = span {
+        err.span_label(span, message);
+    } else {
+        err.note(message);
+    }
+}
+
+#[instrument(level = "trace", skip(infcx))]
+pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
+    infcx: &'a InferCtxt<'tcx>,
+    generic_param_scope: LocalDefId,
+    span: Span,
+    hidden_ty: Ty<'tcx>,
+    hidden_region: ty::Region<'tcx>,
+    opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
+) -> Diag<'a> {
+    let tcx = infcx.tcx;
+    let mut err = infcx.dcx().create_err(errors::OpaqueCapturesLifetime {
+        span,
+        opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args),
+        opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
+    });
+
+    // Explain the region we are capturing.
+    match *hidden_region {
+        ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReStatic => {
+            // Assuming regionck succeeded (*), we ought to always be
+            // capturing *some* region from the fn header, and hence it
+            // ought to be free. So under normal circumstances, we will go
+            // down this path which gives a decent human readable
+            // explanation.
+            //
+            // (*) if not, the `tainted_by_errors` field would be set to
+            // `Some(ErrorGuaranteed)` in any case, so we wouldn't be here at all.
+            explain_free_region(
+                tcx,
+                &mut err,
+                generic_param_scope,
+                &format!("hidden type `{hidden_ty}` captures "),
+                hidden_region,
+                "",
+            );
+            if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
+                let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
+                nice_region_error::suggest_new_region_bound(
+                    tcx,
+                    &mut err,
+                    fn_returns,
+                    hidden_region.to_string(),
+                    None,
+                    format!("captures `{hidden_region}`"),
+                    None,
+                    Some(reg_info.def_id),
+                )
+            }
+        }
+        ty::RePlaceholder(_) => {
+            explain_free_region(
+                tcx,
+                &mut err,
+                generic_param_scope,
+                &format!("hidden type `{}` captures ", hidden_ty),
+                hidden_region,
+                "",
+            );
+        }
+        ty::ReError(_) => {
+            err.downgrade_to_delayed_bug();
+        }
+        _ => {
+            // Ugh. This is a painful case: the hidden region is not one
+            // that we can easily summarize or explain. This can happen
+            // in a case like
+            // `tests/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`:
+            //
+            // ```
+            // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> {
+            //   if condition() { a } else { b }
+            // }
+            // ```
+            //
+            // Here the captured lifetime is the intersection of `'a` and
+            // `'b`, which we can't quite express.
+
+            // We can at least report a really cryptic error for now.
+            note_and_explain_region(
+                tcx,
+                &mut err,
+                generic_param_scope,
+                &format!("hidden type `{hidden_ty}` captures "),
+                hidden_region,
+                "",
+                None,
+            );
+        }
+    }
+
+    err
+}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index ff593d7ffb7..9f55939c165 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -53,6 +53,7 @@ use type_variable::TypeVariableOrigin;
 
 pub mod at;
 pub mod canonical;
+mod context;
 pub mod error_reporting;
 pub mod free_regions;
 mod freshen;
@@ -767,19 +768,9 @@ impl<'tcx> InferCtxt<'tcx> {
             .collect()
     }
 
-    pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool
-    where
-        T: at::ToTrace<'tcx>,
-    {
-        let origin = &ObligationCause::dummy();
-        self.probe(|_| {
-            // We're only answering whether there could be a subtyping relation, and with
-            // opaque types, "there could be one", via registering a hidden type.
-            self.at(origin, param_env).sub(DefineOpaqueTypes::Yes, expected, actual).is_ok()
-        })
-    }
-
-    pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
+    // FIXME(-Znext-solver): Get rid of this method, it's never correct. Either that,
+    // or we need to process the obligations.
+    pub fn can_eq_shallow<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
     where
         T: at::ToTrace<'tcx>,
     {
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
deleted file mode 100644
index 6bab3ad6ba3..00000000000
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ /dev/null
@@ -1,266 +0,0 @@
-// The outlines relation `T: 'a` or `'a: 'b`. This code frequently
-// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
-// RFC for reference.
-
-use rustc_data_structures::sso::SsoHashSet;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{GenericArg, GenericArgKind};
-use smallvec::{smallvec, SmallVec};
-
-#[derive(Debug)]
-pub enum Component<'tcx> {
-    Region(ty::Region<'tcx>),
-    Param(ty::ParamTy),
-    Placeholder(ty::PlaceholderType),
-    UnresolvedInferenceVariable(ty::InferTy),
-
-    // Projections like `T::Foo` are tricky because a constraint like
-    // `T::Foo: 'a` can be satisfied in so many ways. There may be a
-    // where-clause that says `T::Foo: 'a`, or the defining trait may
-    // include a bound like `type Foo: 'static`, or -- in the most
-    // conservative way -- we can prove that `T: 'a` (more generally,
-    // that all components in the projection outlive `'a`). This code
-    // is not in a position to judge which is the best technique, so
-    // we just product the projection as a component and leave it to
-    // the consumer to decide (but see `EscapingProjection` below).
-    Alias(ty::AliasTy<'tcx>),
-
-    // In the case where a projection has escaping regions -- meaning
-    // regions bound within the type itself -- we always use
-    // the most conservative rule, which requires that all components
-    // outlive the bound. So for example if we had a type like this:
-    //
-    //     for<'a> Trait1<  <T as Trait2<'a,'b>>::Foo  >
-    //                      ~~~~~~~~~~~~~~~~~~~~~~~~~
-    //
-    // then the inner projection (underlined) has an escaping region
-    // `'a`. We consider that outer trait `'c` to meet a bound if `'b`
-    // outlives `'b: 'c`, and we don't consider whether the trait
-    // declares that `Foo: 'static` etc. Therefore, we just return the
-    // free components of such a projection (in this case, `'b`).
-    //
-    // However, in the future, we may want to get smarter, and
-    // actually return a "higher-ranked projection" here. Therefore,
-    // we mark that these components are part of an escaping
-    // projection, so that implied bounds code can avoid relying on
-    // them. This gives us room to improve the regionck reasoning in
-    // the future without breaking backwards compat.
-    EscapingAlias(Vec<Component<'tcx>>),
-}
-
-/// Push onto `out` all the things that must outlive `'a` for the condition
-/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
-pub fn push_outlives_components<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty0: Ty<'tcx>,
-    out: &mut SmallVec<[Component<'tcx>; 4]>,
-) {
-    let mut visited = SsoHashSet::new();
-    compute_components(tcx, ty0, out, &mut visited);
-    debug!("components({:?}) = {:?}", ty0, out);
-}
-
-fn compute_components<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-    out: &mut SmallVec<[Component<'tcx>; 4]>,
-    visited: &mut SsoHashSet<GenericArg<'tcx>>,
-) {
-    // Descend through the types, looking for the various "base"
-    // components and collecting them into `out`. This is not written
-    // with `collect()` because of the need to sometimes skip subtrees
-    // in the `subtys` iterator (e.g., when encountering a
-    // projection).
-    match *ty.kind() {
-            ty::FnDef(_, args) => {
-                // HACK(eddyb) ignore lifetimes found shallowly in `args`.
-                // This is inconsistent with `ty::Adt` (including all args)
-                // and with `ty::Closure` (ignoring all args other than
-                // upvars, of which a `ty::FnDef` doesn't have any), but
-                // consistent with previous (accidental) behavior.
-                // See https://github.com/rust-lang/rust/issues/70917
-                // for further background and discussion.
-                for child in args {
-                    match child.unpack() {
-                        GenericArgKind::Type(ty) => {
-                            compute_components(tcx, ty, out, visited);
-                        }
-                        GenericArgKind::Lifetime(_) => {}
-                        GenericArgKind::Const(_) => {
-                            compute_components_recursive(tcx, child, out, visited);
-                        }
-                    }
-                }
-            }
-
-            ty::Pat(element, _) |
-            ty::Array(element, _) => {
-                // Don't look into the len const as it doesn't affect regions
-                compute_components(tcx, element, out, visited);
-            }
-
-            ty::Closure(_, args) => {
-                let tupled_ty = args.as_closure().tupled_upvars_ty();
-                compute_components(tcx, tupled_ty, out, visited);
-            }
-
-            ty::CoroutineClosure(_, args) => {
-                let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty();
-                compute_components(tcx, tupled_ty, out, visited);
-            }
-
-            ty::Coroutine(_, args) => {
-                // Same as the closure case
-                let tupled_ty = args.as_coroutine().tupled_upvars_ty();
-                compute_components(tcx, tupled_ty, out, visited);
-
-                // We ignore regions in the coroutine interior as we don't
-                // want these to affect region inference
-            }
-
-            // All regions are bound inside a witness
-            ty::CoroutineWitness(..) => (),
-
-            // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
-            // is implied by the environment is done in regionck.
-            ty::Param(p) => {
-                out.push(Component::Param(p));
-            }
-
-            ty::Placeholder(p) => {
-                out.push(Component::Placeholder(p));
-            }
-
-            // For projections, we prefer to generate an obligation like
-            // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
-            // regionck more ways to prove that it holds. However,
-            // regionck is not (at least currently) prepared to deal with
-            // higher-ranked regions that may appear in the
-            // trait-ref. Therefore, if we see any higher-ranked regions,
-            // we simply fallback to the most restrictive rule, which
-            // requires that `Pi: 'a` for all `i`.
-            ty::Alias(_, alias_ty) => {
-                if !alias_ty.has_escaping_bound_vars() {
-                    // best case: no escaping regions, so push the
-                    // projection and skip the subtree (thus generating no
-                    // constraints for Pi). This defers the choice between
-                    // the rules OutlivesProjectionEnv,
-                    // OutlivesProjectionTraitDef, and
-                    // OutlivesProjectionComponents to regionck.
-                    out.push(Component::Alias(alias_ty));
-                } else {
-                    // fallback case: hard code
-                    // OutlivesProjectionComponents. Continue walking
-                    // through and constrain Pi.
-                    let mut subcomponents = smallvec![];
-                    let mut subvisited = SsoHashSet::new();
-                    compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited);
-                    out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
-                }
-            }
-
-            // We assume that inference variables are fully resolved.
-            // So, if we encounter an inference variable, just record
-            // the unresolved variable as a component.
-            ty::Infer(infer_ty) => {
-                out.push(Component::UnresolvedInferenceVariable(infer_ty));
-            }
-
-            // Most types do not introduce any region binders, nor
-            // involve any other subtle cases, and so the WF relation
-            // simply constraints any regions referenced directly by
-            // the type and then visits the types that are lexically
-            // contained within. (The comments refer to relevant rules
-            // from RFC1214.)
-            ty::Bool |            // OutlivesScalar
-            ty::Char |            // OutlivesScalar
-            ty::Int(..) |         // OutlivesScalar
-            ty::Uint(..) |        // OutlivesScalar
-            ty::Float(..) |       // OutlivesScalar
-            ty::Never |           // ...
-            ty::Adt(..) |         // OutlivesNominalType
-            ty::Foreign(..) |     // OutlivesNominalType
-            ty::Str |             // OutlivesScalar (ish)
-            ty::Slice(..) |       // ...
-            ty::RawPtr(..) |      // ...
-            ty::Ref(..) |         // OutlivesReference
-            ty::Tuple(..) |       // ...
-            ty::FnPtr(_) |        // OutlivesFunction (*)
-            ty::Dynamic(..) |     // OutlivesObject, OutlivesFragment (*)
-            ty::Bound(..) |
-            ty::Error(_) => {
-                // (*) Function pointers and trait objects are both binders.
-                // In the RFC, this means we would add the bound regions to
-                // the "bound regions list". In our representation, no such
-                // list is maintained explicitly, because bound regions
-                // themselves can be readily identified.
-                compute_components_recursive(tcx, ty.into(), out, visited);
-            }
-        }
-}
-
-/// Collect [Component]s for *all* the args of `parent`.
-///
-/// This should not be used to get the components of `parent` itself.
-/// Use [push_outlives_components] instead.
-pub(super) fn compute_alias_components_recursive<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    alias_ty: Ty<'tcx>,
-    out: &mut SmallVec<[Component<'tcx>; 4]>,
-    visited: &mut SsoHashSet<GenericArg<'tcx>>,
-) {
-    let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
-        unreachable!("can only call `compute_alias_components_recursive` on an alias type")
-    };
-    let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] };
-    for (index, child) in alias_ty.args.iter().enumerate() {
-        if opt_variances.get(index) == Some(&ty::Bivariant) {
-            continue;
-        }
-        if !visited.insert(child) {
-            continue;
-        }
-        match child.unpack() {
-            GenericArgKind::Type(ty) => {
-                compute_components(tcx, ty, out, visited);
-            }
-            GenericArgKind::Lifetime(lt) => {
-                // Ignore higher ranked regions.
-                if !lt.is_bound() {
-                    out.push(Component::Region(lt));
-                }
-            }
-            GenericArgKind::Const(_) => {
-                compute_components_recursive(tcx, child, out, visited);
-            }
-        }
-    }
-}
-
-/// Collect [Component]s for *all* the args of `parent`.
-///
-/// This should not be used to get the components of `parent` itself.
-/// Use [push_outlives_components] instead.
-fn compute_components_recursive<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    parent: GenericArg<'tcx>,
-    out: &mut SmallVec<[Component<'tcx>; 4]>,
-    visited: &mut SsoHashSet<GenericArg<'tcx>>,
-) {
-    for child in parent.walk_shallow(visited) {
-        match child.unpack() {
-            GenericArgKind::Type(ty) => {
-                compute_components(tcx, ty, out, visited);
-            }
-            GenericArgKind::Lifetime(lt) => {
-                // Ignore higher ranked regions.
-                if !lt.is_bound() {
-                    out.push(Component::Region(lt));
-                }
-            }
-            GenericArgKind::Const(_) => {
-                compute_components_recursive(tcx, child, out, visited);
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 48d006e7fbc..89ff4604560 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -8,7 +8,6 @@ use crate::infer::lexical_region_resolve;
 use rustc_middle::traits::query::{NoSolution, OutlivesBound};
 use rustc_middle::ty;
 
-pub mod components;
 pub mod env;
 pub mod for_liveness;
 pub mod obligations;
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 32c790523b6..d82ae7b4fb8 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -59,7 +59,6 @@
 //! might later infer `?U` to something like `&'b u32`, which would
 //! imply that `'b: 'a`.
 
-use crate::infer::outlives::components::{push_outlives_components, Component};
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::outlives::verify::VerifyBoundCx;
 use crate::infer::resolve::OpportunisticRegionResolver;
@@ -75,6 +74,7 @@ use rustc_middle::ty::{
 };
 use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate};
 use rustc_span::DUMMY_SP;
+use rustc_type_ir::outlives::{push_outlives_components, Component};
 use smallvec::smallvec;
 
 use super::env::OutlivesEnvironment;
@@ -291,7 +291,7 @@ where
     fn components_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
-        components: &[Component<'tcx>],
+        components: &[Component<TyCtxt<'tcx>>],
         region: ty::Region<'tcx>,
         category: ConstraintCategory<'tcx>,
     ) {
@@ -471,7 +471,7 @@ where
         // projection outlive; in some cases, this may add insufficient
         // edges into the inference graph, leading to inference failures
         // even though a satisfactory solution exists.
-        let verify_bound = self.verify_bound.alias_bound(alias_ty, &mut Default::default());
+        let verify_bound = self.verify_bound.alias_bound(alias_ty);
         debug!("alias_must_outlive: pushing {:?}", verify_bound);
         self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound);
     }
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 7e977b9b954..2392a82025a 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -1,10 +1,8 @@
-use crate::infer::outlives::components::{compute_alias_components_recursive, Component};
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::region_constraints::VerifyIfEq;
 use crate::infer::{GenericKind, VerifyBound};
-use rustc_data_structures::sso::SsoHashSet;
-use rustc_middle::ty::GenericArg;
 use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
+use rustc_type_ir::outlives::{compute_alias_components_recursive, Component};
 
 use smallvec::smallvec;
 
@@ -99,12 +97,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
     }
 
-    #[instrument(level = "debug", skip(self, visited))]
-    pub fn alias_bound(
-        &self,
-        alias_ty: ty::AliasTy<'tcx>,
-        visited: &mut SsoHashSet<GenericArg<'tcx>>,
-    ) -> VerifyBound<'tcx> {
+    #[instrument(level = "debug", skip(self))]
+    pub fn alias_bound(&self, alias_ty: ty::AliasTy<'tcx>) -> VerifyBound<'tcx> {
         let alias_ty_as_ty = alias_ty.to_ty(self.tcx);
 
         // Search the env for where clauses like `P: 'a`.
@@ -130,21 +124,17 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         // see the extensive comment in projection_must_outlive
         let recursive_bound = {
             let mut components = smallvec![];
-            compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components, visited);
-            self.bound_from_components(&components, visited)
+            compute_alias_components_recursive(self.tcx, alias_ty_as_ty, &mut components);
+            self.bound_from_components(&components)
         };
 
         VerifyBound::AnyBound(env_bounds.chain(definition_bounds).collect()).or(recursive_bound)
     }
 
-    fn bound_from_components(
-        &self,
-        components: &[Component<'tcx>],
-        visited: &mut SsoHashSet<GenericArg<'tcx>>,
-    ) -> VerifyBound<'tcx> {
+    fn bound_from_components(&self, components: &[Component<TyCtxt<'tcx>>]) -> VerifyBound<'tcx> {
         let mut bounds = components
             .iter()
-            .map(|component| self.bound_from_single_component(component, visited))
+            .map(|component| self.bound_from_single_component(component))
             // Remove bounds that must hold, since they are not interesting.
             .filter(|bound| !bound.must_hold());
 
@@ -158,8 +148,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
 
     fn bound_from_single_component(
         &self,
-        component: &Component<'tcx>,
-        visited: &mut SsoHashSet<GenericArg<'tcx>>,
+        component: &Component<TyCtxt<'tcx>>,
     ) -> VerifyBound<'tcx> {
         match *component {
             Component::Region(lt) => VerifyBound::OutlivedBy(lt),
@@ -167,10 +156,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
             Component::Placeholder(placeholder_ty) => {
                 self.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty))
             }
-            Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited),
-            Component::EscapingAlias(ref components) => {
-                self.bound_from_components(components, visited)
-            }
+            Component::Alias(alias_ty) => self.alias_bound(alias_ty),
+            Component::EscapingAlias(ref components) => self.bound_from_components(components),
             Component::UnresolvedInferenceVariable(v) => {
                 // Ignore this, we presume it will yield an error later, since
                 // if a type variable is not resolved by this point it never
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 0a2e85cc891..c93b89756f9 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -18,11 +18,13 @@
 //! On success, the  LUB/GLB operations return the appropriate bound. The
 //! return value of `Equate` or `Sub` shouldn't really be used.
 
+pub use rustc_next_trait_solver::relate::combine::*;
+
 use super::glb::Glb;
 use super::lub::Lub;
 use super::type_relating::TypeRelating;
+use super::RelateResult;
 use super::StructurallyRelateAliases;
-use super::{RelateResult, TypeRelation};
 use crate::infer::relate;
 use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
 use crate::traits::{Obligation, PredicateObligation};
@@ -32,7 +34,6 @@ use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
 use rustc_middle::ty::{IntType, UintType};
-use rustc_span::Span;
 
 #[derive(Clone)]
 pub struct CombineFields<'infcx, 'tcx> {
@@ -76,7 +77,7 @@ impl<'tcx> InferCtxt<'tcx> {
         b: Ty<'tcx>,
     ) -> RelateResult<'tcx, Ty<'tcx>>
     where
-        R: PredicateEmittingRelation<'tcx>,
+        R: PredicateEmittingRelation<InferCtxt<'tcx>>,
     {
         debug_assert!(!a.has_escaping_bound_vars());
         debug_assert!(!b.has_escaping_bound_vars());
@@ -171,7 +172,7 @@ impl<'tcx> InferCtxt<'tcx> {
         b: ty::Const<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>>
     where
-        R: PredicateEmittingRelation<'tcx>,
+        R: PredicateEmittingRelation<InferCtxt<'tcx>>,
     {
         debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
         debug_assert!(!a.has_escaping_bound_vars());
@@ -323,30 +324,3 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         )
     }
 }
-
-pub trait PredicateEmittingRelation<'tcx>: TypeRelation<TyCtxt<'tcx>> {
-    fn span(&self) -> Span;
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx>;
-
-    /// Whether aliases should be related structurally. This is pretty much
-    /// always `No` unless you're equating in some specific locations of the
-    /// new solver. See the comments in these use-cases for more details.
-    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
-
-    /// Register obligations that must hold in order for this relation to hold
-    fn register_goals(
-        &mut self,
-        obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
-    );
-
-    /// Register predicates that must hold in order for this relation to hold.
-    /// This uses the default `param_env` of the obligation.
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
-    );
-
-    /// Register `AliasRelate` obligation(s) that both types must be related to each other.
-    fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
-}
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index d6e57d85387..fe3b8d60fb9 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -30,7 +30,7 @@ impl<'tcx> InferCtxt<'tcx> {
     /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
     /// other usecases (i.e. setting the value of a type var).
     #[instrument(level = "debug", skip(self, relation))]
-    pub fn instantiate_ty_var<R: PredicateEmittingRelation<'tcx>>(
+    pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
         &self,
         relation: &mut R,
         target_is_expected: bool,
@@ -178,7 +178,7 @@ impl<'tcx> InferCtxt<'tcx> {
     ///
     /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
     #[instrument(level = "debug", skip(self, relation))]
-    pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<'tcx>>(
+    pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
         &self,
         relation: &mut R,
         target_is_expected: bool,
diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs
index 067004ecaeb..5bb8a113e17 100644
--- a/compiler/rustc_infer/src/infer/relate/glb.rs
+++ b/compiler/rustc_infer/src/infer/relate/glb.rs
@@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
     }
 }
 
-impl<'tcx> PredicateEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
+impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Glb<'_, '_, 'tcx> {
     fn span(&self) -> Span {
         self.fields.trace.span()
     }
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index 6cc8d6d910a..46e7466141a 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Ty};
 ///
 /// GLB moves "down" the lattice (to smaller values); LUB moves
 /// "up" the lattice (to bigger values).
-pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<'tcx> {
+pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>> {
     fn infcx(&self) -> &'f InferCtxt<'tcx>;
 
     fn cause(&self) -> &ObligationCause<'tcx>;
diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs
index 2184416b4cc..94c1464817f 100644
--- a/compiler/rustc_infer/src/infer/relate/lub.rs
+++ b/compiler/rustc_infer/src/infer/relate/lub.rs
@@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
     }
 }
 
-impl<'tcx> PredicateEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
+impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Lub<'_, '_, 'tcx> {
     fn span(&self) -> Span {
         self.fields.trace.span()
     }
diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs
index 41cc945492d..dd97dc061fe 100644
--- a/compiler/rustc_infer/src/infer/relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/relate/mod.rs
@@ -2,11 +2,13 @@
 //! (except for some relations used for diagnostics and heuristics in the compiler).
 //! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc).
 
-pub use rustc_middle::ty::relate::*;
+pub use rustc_middle::ty::relate::RelateResult;
+pub use rustc_next_trait_solver::relate::*;
 
 pub use self::combine::CombineFields;
 pub use self::combine::PredicateEmittingRelation;
 
+#[allow(hidden_glob_reexports)]
 pub(super) mod combine;
 mod generalize;
 mod glb;
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index f2bec9392d5..e206f530519 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -1,7 +1,7 @@
 use super::combine::CombineFields;
 use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
 use crate::infer::BoundRegionConversionTime::HigherRankedType;
-use crate::infer::{DefineOpaqueTypes, SubregionOrigin};
+use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
 use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::relate::{
     relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation,
@@ -296,7 +296,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
     }
 }
 
-impl<'tcx> PredicateEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
+impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
     fn span(&self) -> Span {
         self.fields.trace.span()
     }
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 24cf9f03fcd..f54d0418595 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -1,11 +1,10 @@
-use smallvec::smallvec;
-
-use crate::infer::outlives::components::{push_outlives_components, Component};
 use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
+use rustc_middle::ty::ToPolyTraitRef;
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
+pub use rustc_type_ir::elaborate::*;
 
 pub fn anonymize_predicate<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -63,51 +62,9 @@ impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// `Elaboration` iterator
-///////////////////////////////////////////////////////////////////////////
-
-/// "Elaboration" is the process of identifying all the predicates that
-/// are implied by a source predicate. Currently, this basically means
-/// walking the "supertraits" and other similar assumptions. For example,
-/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
-/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
-/// `T: Foo`, then we know that `T: 'static`.
-pub struct Elaborator<'tcx, O> {
-    stack: Vec<O>,
-    visited: PredicateSet<'tcx>,
-    mode: Filter,
-}
-
-enum Filter {
-    All,
-    OnlySelf,
-    OnlySelfThatDefines(Ident),
-}
-
-/// Describes how to elaborate an obligation into a sub-obligation.
-///
 /// For [`Obligation`], a sub-obligation is combined with the current obligation's
-/// param-env and cause code. For [`ty::Predicate`], none of this is needed, since
-/// there is no param-env or cause code to copy over.
-pub trait Elaboratable<'tcx> {
-    fn predicate(&self) -> ty::Predicate<'tcx>;
-
-    // Makes a new `Self` but with a different clause that comes from elaboration.
-    fn child(&self, clause: ty::Clause<'tcx>) -> Self;
-
-    // Makes a new `Self` but with a different clause and a different cause
-    // code (if `Self` has one, such as [`PredicateObligation`]).
-    fn child_with_derived_cause(
-        &self,
-        clause: ty::Clause<'tcx>,
-        span: Span,
-        parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
-        index: usize,
-    ) -> Self;
-}
-
-impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
+/// param-env and cause code.
+impl<'tcx> Elaboratable<TyCtxt<'tcx>> for PredicateObligation<'tcx> {
     fn predicate(&self) -> ty::Predicate<'tcx> {
         self.predicate
     }
@@ -145,279 +102,6 @@ impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
     }
 }
 
-impl<'tcx> Elaboratable<'tcx> for ty::Predicate<'tcx> {
-    fn predicate(&self) -> ty::Predicate<'tcx> {
-        *self
-    }
-
-    fn child(&self, clause: ty::Clause<'tcx>) -> Self {
-        clause.as_predicate()
-    }
-
-    fn child_with_derived_cause(
-        &self,
-        clause: ty::Clause<'tcx>,
-        _span: Span,
-        _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
-        _index: usize,
-    ) -> Self {
-        clause.as_predicate()
-    }
-}
-
-impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) {
-    fn predicate(&self) -> ty::Predicate<'tcx> {
-        self.0
-    }
-
-    fn child(&self, clause: ty::Clause<'tcx>) -> Self {
-        (clause.as_predicate(), self.1)
-    }
-
-    fn child_with_derived_cause(
-        &self,
-        clause: ty::Clause<'tcx>,
-        _span: Span,
-        _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
-        _index: usize,
-    ) -> Self {
-        (clause.as_predicate(), self.1)
-    }
-}
-
-impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) {
-    fn predicate(&self) -> ty::Predicate<'tcx> {
-        self.0.as_predicate()
-    }
-
-    fn child(&self, clause: ty::Clause<'tcx>) -> Self {
-        (clause, self.1)
-    }
-
-    fn child_with_derived_cause(
-        &self,
-        clause: ty::Clause<'tcx>,
-        _span: Span,
-        _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
-        _index: usize,
-    ) -> Self {
-        (clause, self.1)
-    }
-}
-
-impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> {
-    fn predicate(&self) -> ty::Predicate<'tcx> {
-        self.as_predicate()
-    }
-
-    fn child(&self, clause: ty::Clause<'tcx>) -> Self {
-        clause
-    }
-
-    fn child_with_derived_cause(
-        &self,
-        clause: ty::Clause<'tcx>,
-        _span: Span,
-        _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
-        _index: usize,
-    ) -> Self {
-        clause
-    }
-}
-
-pub fn elaborate<'tcx, O: Elaboratable<'tcx>>(
-    tcx: TyCtxt<'tcx>,
-    obligations: impl IntoIterator<Item = O>,
-) -> Elaborator<'tcx, O> {
-    let mut elaborator =
-        Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), mode: Filter::All };
-    elaborator.extend_deduped(obligations);
-    elaborator
-}
-
-impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
-    fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
-        // Only keep those bounds that we haven't already seen.
-        // This is necessary to prevent infinite recursion in some
-        // cases. One common case is when people define
-        // `trait Sized: Sized { }` rather than `trait Sized { }`.
-        // let visited = &mut self.visited;
-        self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate())));
-    }
-
-    /// Filter to only the supertraits of trait predicates, i.e. only the predicates
-    /// that have `Self` as their self type, instead of all implied predicates.
-    pub fn filter_only_self(mut self) -> Self {
-        self.mode = Filter::OnlySelf;
-        self
-    }
-
-    /// Filter to only the supertraits of trait predicates that define the assoc_ty.
-    pub fn filter_only_self_that_defines(mut self, assoc_ty: Ident) -> Self {
-        self.mode = Filter::OnlySelfThatDefines(assoc_ty);
-        self
-    }
-
-    fn elaborate(&mut self, elaboratable: &O) {
-        let tcx = self.visited.tcx;
-
-        // We only elaborate clauses.
-        let Some(clause) = elaboratable.predicate().as_clause() else {
-            return;
-        };
-
-        let bound_clause = clause.kind();
-        match bound_clause.skip_binder() {
-            ty::ClauseKind::Trait(data) => {
-                // Negative trait bounds do not imply any supertrait bounds
-                if data.polarity != ty::PredicatePolarity::Positive {
-                    return;
-                }
-                // Get predicates implied by the trait, or only super predicates if we only care about self predicates.
-                let predicates = match self.mode {
-                    Filter::All => tcx.explicit_implied_predicates_of(data.def_id()),
-                    Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()),
-                    Filter::OnlySelfThatDefines(ident) => {
-                        tcx.explicit_supertraits_containing_assoc_item((data.def_id(), ident))
-                    }
-                };
-
-                let obligations =
-                    predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
-                        elaboratable.child_with_derived_cause(
-                            clause.instantiate_supertrait(tcx, bound_clause.rebind(data.trait_ref)),
-                            span,
-                            bound_clause.rebind(data),
-                            index,
-                        )
-                    });
-                debug!(?data, ?obligations, "super_predicates");
-                self.extend_deduped(obligations);
-            }
-            ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
-                // We know that `T: 'a` for some type `T`. We can
-                // often elaborate this. For example, if we know that
-                // `[U]: 'a`, that implies that `U: 'a`. Similarly, if
-                // we know `&'a U: 'b`, then we know that `'a: 'b` and
-                // `U: 'b`.
-                //
-                // We can basically ignore bound regions here. So for
-                // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
-                // `'a: 'b`.
-
-                // Ignore `for<'a> T: 'a` -- we might in the future
-                // consider this as evidence that `T: 'static`, but
-                // I'm a bit wary of such constructions and so for now
-                // I want to be conservative. --nmatsakis
-                if r_min.is_bound() {
-                    return;
-                }
-
-                let mut components = smallvec![];
-                push_outlives_components(tcx, ty_max, &mut components);
-                self.extend_deduped(
-                    components
-                        .into_iter()
-                        .filter_map(|component| match component {
-                            Component::Region(r) => {
-                                if r.is_bound() {
-                                    None
-                                } else {
-                                    Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
-                                        r, r_min,
-                                    )))
-                                }
-                            }
-
-                            Component::Param(p) => {
-                                let ty = Ty::new_param(tcx, p.index, p.name);
-                                Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
-                            }
-
-                            Component::Placeholder(p) => {
-                                let ty = Ty::new_placeholder(tcx, p);
-                                Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
-                            }
-
-                            Component::UnresolvedInferenceVariable(_) => None,
-
-                            Component::Alias(alias_ty) => {
-                                // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
-                                // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
-                                Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
-                                    alias_ty.to_ty(tcx),
-                                    r_min,
-                                )))
-                            }
-
-                            Component::EscapingAlias(_) => {
-                                // We might be able to do more here, but we don't
-                                // want to deal with escaping vars right now.
-                                None
-                            }
-                        })
-                        .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(tcx))),
-                );
-            }
-            ty::ClauseKind::RegionOutlives(..) => {
-                // Nothing to elaborate from `'a: 'b`.
-            }
-            ty::ClauseKind::WellFormed(..) => {
-                // Currently, we do not elaborate WF predicates,
-                // although we easily could.
-            }
-            ty::ClauseKind::Projection(..) => {
-                // Nothing to elaborate in a projection predicate.
-            }
-            ty::ClauseKind::ConstEvaluatable(..) => {
-                // Currently, we do not elaborate const-evaluatable
-                // predicates.
-            }
-            ty::ClauseKind::ConstArgHasType(..) => {
-                // Nothing to elaborate
-            }
-        }
-    }
-}
-
-impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> {
-    type Item = O;
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (self.stack.len(), None)
-    }
-
-    fn next(&mut self) -> Option<Self::Item> {
-        // Extract next item from top-most stack frame, if any.
-        if let Some(obligation) = self.stack.pop() {
-            self.elaborate(&obligation);
-            Some(obligation)
-        } else {
-            None
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Supertrait iterator
-///////////////////////////////////////////////////////////////////////////
-
-pub fn supertraits<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
-) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits()
-}
-
-pub fn transitive_bounds<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
-) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
-        .filter_only_self()
-        .filter_to_traits()
-}
-
 /// A specialized variant of `elaborate` that only elaborates trait references that may
 /// define the given associated item with the name `assoc_name`. It uses the
 /// `explicit_supertraits_containing_assoc_item` query to avoid enumerating super-predicates that
@@ -427,42 +111,28 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
     assoc_name: Ident,
-) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
-        .filter_only_self_that_defines(assoc_name)
-        .filter_to_traits()
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Other
-///////////////////////////////////////////////////////////////////////////
-
-impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> {
-    fn filter_to_traits(self) -> FilterToTraits<Self> {
-        FilterToTraits { base_iterator: self }
-    }
-}
-
-/// A filter around an iterator of predicates that makes it yield up
-/// just trait references.
-pub struct FilterToTraits<I> {
-    base_iterator: I,
-}
+) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
+    let mut seen = FxHashSet::default();
+    let mut stack: Vec<_> = trait_refs.collect();
+
+    std::iter::from_fn(move || {
+        while let Some(trait_ref) = stack.pop() {
+            if !seen.insert(tcx.anonymize_bound_vars(trait_ref)) {
+                continue;
+            }
 
-impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
-    type Item = ty::PolyTraitRef<'tcx>;
+            stack.extend(
+                tcx.explicit_supertraits_containing_assoc_item((trait_ref.def_id(), assoc_name))
+                    .instantiate_own_identity()
+                    .map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref))
+                    .filter_map(|clause| clause.as_trait_clause())
+                    // FIXME: Negative supertraits are elaborated here lol
+                    .map(|trait_pred| trait_pred.to_poly_trait_ref()),
+            );
 
-    fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
-        while let Some(pred) = self.base_iterator.next() {
-            if let Some(data) = pred.as_trait_clause() {
-                return Some(data.map_bound(|t| t.trait_ref));
-            }
+            return Some(trait_ref);
         }
-        None
-    }
 
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (_, upper) = self.base_iterator.size_hint();
-        (0, upper)
-    }
+        None
+    })
 }
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 38f64ebb04e..e37b30749ab 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -16,7 +16,7 @@ pub mod util;
 pub use callbacks::setup_callbacks;
 pub use interface::{run_compiler, Config};
 pub use passes::DEFAULT_QUERY_PROVIDERS;
-pub use queries::Queries;
+pub use queries::{Linker, Queries};
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index cfd4304e893..821e8ee7ba5 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -65,12 +65,6 @@ impl<'a, 'tcx> QueryResult<'a, &'tcx GlobalCtxt<'tcx>> {
     }
 }
 
-impl<T> Default for Query<T> {
-    fn default() -> Self {
-        Query { result: RefCell::new(None) }
-    }
-}
-
 pub struct Queries<'tcx> {
     compiler: &'tcx Compiler,
     gcx_cell: OnceLock<GlobalCtxt<'tcx>>,
@@ -90,8 +84,8 @@ impl<'tcx> Queries<'tcx> {
             gcx_cell: OnceLock::new(),
             arena: WorkerLocal::new(|_| Arena::default()),
             hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
-            parse: Default::default(),
-            gcx: Default::default(),
+            parse: Query { result: RefCell::new(None) },
+            gcx: Query { result: RefCell::new(None) },
         }
     }
 
@@ -116,23 +110,6 @@ impl<'tcx> Queries<'tcx> {
             )
         })
     }
-
-    pub fn codegen_and_build_linker(&'tcx self) -> Result<Linker> {
-        self.global_ctxt()?.enter(|tcx| {
-            let ongoing_codegen = passes::start_codegen(&*self.compiler.codegen_backend, tcx)?;
-
-            Ok(Linker {
-                dep_graph: tcx.dep_graph.clone(),
-                output_filenames: tcx.output_filenames(()).clone(),
-                crate_hash: if tcx.needs_crate_hash() {
-                    Some(tcx.crate_hash(LOCAL_CRATE))
-                } else {
-                    None
-                },
-                ongoing_codegen,
-            })
-        })
-    }
 }
 
 pub struct Linker {
@@ -144,6 +121,36 @@ pub struct Linker {
 }
 
 impl Linker {
+    pub fn codegen_and_build_linker(
+        tcx: TyCtxt<'_>,
+        codegen_backend: &dyn CodegenBackend,
+    ) -> Result<Linker> {
+        let ongoing_codegen = passes::start_codegen(codegen_backend, tcx)?;
+
+        // This must run after monomorphization so that all generic types
+        // have been instantiated.
+        if tcx.sess.opts.unstable_opts.print_type_sizes {
+            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);
+        }
+
+        Ok(Linker {
+            dep_graph: tcx.dep_graph.clone(),
+            output_filenames: tcx.output_filenames(()).clone(),
+            crate_hash: if tcx.needs_crate_hash() {
+                Some(tcx.crate_hash(LOCAL_CRATE))
+            } else {
+                None
+            },
+            ongoing_codegen,
+        })
+    }
+
     pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) -> Result<()> {
         let (codegen_results, work_products) =
             codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames);
@@ -197,7 +204,7 @@ impl Compiler {
         F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T,
     {
         // Must declare `_timer` first so that it is dropped after `queries`.
-        let mut _timer = None;
+        let _timer;
         let queries = Queries::new(self);
         let ret = f(&queries);
 
@@ -220,7 +227,7 @@ impl Compiler {
 
         // The timer's lifetime spans the dropping of `queries`, which contains
         // the global context.
-        _timer = Some(self.sess.timer("free_global_ctxt"));
+        _timer = self.sess.timer("free_global_ctxt");
         if let Err((path, error)) = queries.finish() {
             self.sess.dcx().emit_fatal(errors::FailedWritingFile { path: &path, error });
         }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 9bd67a1154b..e2ba75dfd19 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -757,7 +757,6 @@ fn test_unstable_options_tracking_hash() {
     // tidy-alphabetical-start
     tracked!(allow_features, Some(vec![String::from("lang_items")]));
     tracked!(always_encode_mir, true);
-    tracked!(asm_comments, true);
     tracked!(assume_incomplete_release, true);
     tracked!(binary_dep_depinfo, true);
     tracked!(box_noalias, false);
@@ -862,6 +861,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(uninit_const_chunk_threshold, 123);
     tracked!(unleash_the_miri_inside_of_you, true);
     tracked!(use_ctors_section, Some(true));
+    tracked!(verbose_asm, true);
     tracked!(verify_llvm_ir, true);
     tracked!(virtual_function_elimination, true);
     tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 3e952558d29..f048f6fe8ad 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -439,6 +439,9 @@ lint_lintpass_by_hand = implementing `LintPass` by hand
 lint_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
     .note = the macro is defined here
 
+lint_macro_expr_fragment_specifier_2024_migration =
+    the `expr` fragment specifier will accept more expressions in the 2024 edition
+    .suggestion = to keep the existing behavior, use the `expr_2021` fragment specifier
 lint_macro_is_private = macro `{$ident}` is private
 
 lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used
diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs
index 40778542c75..6daee95dda6 100644
--- a/compiler/rustc_lint/src/async_fn_in_trait.rs
+++ b/compiler/rustc_lint/src/async_fn_in_trait.rs
@@ -3,7 +3,7 @@ use crate::LateContext;
 use crate::LateLintPass;
 use rustc_hir as hir;
 use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_trait_selection::traits::error_reporting::suggestions::suggest_desugaring_async_fn_to_impl_future_in_trait;
+use rustc_trait_selection::error_reporting::traits::suggestions::suggest_desugaring_async_fn_to_impl_future_in_trait;
 
 declare_lint! {
     /// The `async_fn_in_trait` lint detects use of `async fn` in the
diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
index c69e680cb64..da36f68fca9 100644
--- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
+++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
@@ -261,10 +261,16 @@ pub(super) fn unexpected_cfg_value(
         lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
     };
 
-    // We don't want to suggest adding values to well known names
-    // since those are defined by rustc it-self. Users can still
-    // do it if they want, but should not encourage them.
-    let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name);
+    // We don't want to encourage people to add values to a well-known names, as these are
+    // defined by rustc/Rust itself. Users can still do this if they wish, but should not be
+    // encouraged to do so.
+    let can_suggest_adding_value = !sess.psess.check_config.well_known_names.contains(&name)
+        // Except when working on rustc or the standard library itself, in which case we want to
+        // suggest adding these cfgs to the "normal" place because of bootstraping reasons. As a
+        // basic heuristic, we use the "cheat" unstable feature enable method and the
+        // non-ui-testing enabled option.
+        || (matches!(sess.psess.unstable_features, rustc_feature::UnstableFeatures::Cheat)
+            && !sess.opts.unstable_opts.ui_testing);
 
     let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
 
@@ -275,14 +281,14 @@ pub(super) fn unexpected_cfg_value(
             } else {
                 Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
             }
-        } else if !is_cfg_a_well_know_name {
+        } else if can_suggest_adding_value {
             Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
         } else {
             None
         };
         lints::unexpected_cfg_value::InvocationHelp::Cargo(help)
     } else {
-        let help = if !is_cfg_a_well_know_name {
+        let help = if can_suggest_adding_value {
             Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
         } else {
             None
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 9110cccdc46..772cc2ff8b9 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -88,7 +88,7 @@ declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]);
 impl LateLintPass<'_> for QueryStability {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return };
-        if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, args) {
+        if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, args) {
             let def_id = instance.def_id();
             if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
                 cx.emit_span_lint(
@@ -393,7 +393,7 @@ impl LateLintPass<'_> for Diagnostics {
         };
 
         // Is the callee marked with `#[rustc_lint_diagnostics]`?
-        let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, fn_gen_args)
+        let has_attr = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args)
             .ok()
             .flatten()
             .is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics));
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 17f9d4421ae..868a44a980a 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -60,6 +60,7 @@ mod late;
 mod let_underscore;
 mod levels;
 mod lints;
+mod macro_expr_fragment_specifier_2024_migration;
 mod map_unit_fn;
 mod methods;
 mod multiple_supertrait_upcastable;
@@ -97,6 +98,7 @@ use impl_trait_overcaptures::ImplTraitOvercaptures;
 use internal::*;
 use invalid_from_utf8::*;
 use let_underscore::*;
+use macro_expr_fragment_specifier_2024_migration::*;
 use map_unit_fn::*;
 use methods::*;
 use multiple_supertrait_upcastable::*;
@@ -170,6 +172,7 @@ early_lint_methods!(
             IncompleteInternalFeatures: IncompleteInternalFeatures,
             RedundantSemicolons: RedundantSemicolons,
             UnusedDocComment: UnusedDocComment,
+            Expr2024: Expr2024,
         ]
     ]
 );
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 7c5640f5959..54c73710eca 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -317,6 +317,13 @@ pub struct BuiltinTypeAliasGenericBounds<'a, 'b> {
     pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(lint_macro_expr_fragment_specifier_2024_migration)]
+pub struct MacroExprFragment2024 {
+    #[suggestion(code = "expr_2021", applicability = "machine-applicable")]
+    pub suggestion: Span,
+}
+
 pub struct BuiltinTypeAliasGenericBoundsSuggestion {
     pub suggestions: Vec<(Span, String)>,
 }
diff --git a/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
new file mode 100644
index 00000000000..867e132b106
--- /dev/null
+++ b/compiler/rustc_lint/src/macro_expr_fragment_specifier_2024_migration.rs
@@ -0,0 +1,155 @@
+//! Migration code for the `expr_fragment_specifier_2024`
+//! rule.
+use tracing::debug;
+
+use rustc_ast::token::Token;
+use rustc_ast::token::TokenKind;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::tokenstream::TokenTree;
+use rustc_session::declare_lint;
+use rustc_session::declare_lint_pass;
+use rustc_session::lint::FutureIncompatibilityReason;
+use rustc_span::edition::Edition;
+use rustc_span::sym;
+
+use crate::lints::MacroExprFragment2024;
+use crate::EarlyLintPass;
+
+declare_lint! {
+    /// The `edition_2024_expr_fragment_specifier` lint detects the use of
+    /// `expr` fragments in macros during migration to the 2024 edition.
+    ///
+    /// The `expr` fragment specifier will accept more expressions in the 2024
+    /// edition. To maintain the behavior from the 2021 edition and earlier, use
+    /// the `expr_2021` fragment specifier.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2021,compile_fail
+    /// #![deny(edition_2024_expr_fragment_specifier)]
+    /// macro_rules! m {
+    ///   ($e:expr) => {
+    ///       $e
+    ///   }
+    /// }
+    ///
+    /// fn main() {
+    ///    m!(1);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Rust [editions] allow the language to evolve without breaking backwards
+    /// compatibility. This lint catches code that uses [macro matcher fragment
+    /// specifiers] that have changed meaning in the 2024 edition. If you switch
+    /// to the new edition without updating the code, your macros may behave
+    /// differently.
+    ///
+    /// In the 2024 edition, the `expr` fragment specifier `expr` will also
+    /// match `const { ... }` blocks. This means if a macro had a pattern that
+    /// matched `$e:expr` and another that matches `const { $e: expr }`, for
+    /// example, that under the 2024 edition the first pattern would match while
+    /// in the 2021 and earlier editions the second pattern would match. To keep
+    /// the old behavior, use the `expr_2021` fragment specifier.
+    ///
+    /// This lint detects macros whose behavior might change due to the changing
+    /// meaning of the `expr` fragment specifier. It is "allow" by default
+    /// because the code is perfectly valid in older editions. The [`cargo fix`]
+    /// tool with the `--edition` flag will switch this lint to "warn" and
+    /// automatically apply the suggested fix from the compiler. This provides a
+    /// completely automated way to update old code for a new edition.
+    ///
+    /// Using `cargo fix --edition` with this lint will ensure that your code
+    /// retains the same behavior. This may not be the desired, as macro authors
+    /// often will want their macros to use the latest grammar for matching
+    /// expressions. Be sure to carefully review changes introduced by this lint
+    /// to ensure the macros implement the desired behavior.
+    ///
+    /// [editions]: https://doc.rust-lang.org/edition-guide/
+    /// [macro matcher fragment specifiers]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html
+    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
+    pub EDITION_2024_EXPR_FRAGMENT_SPECIFIER,
+    Allow,
+    "The `expr` fragment specifier will accept more expressions in the 2024 edition. \
+    To keep the existing behavior, use the `expr_2021` fragment specifier.",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
+        reference: "Migration Guide <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html>",
+    };
+}
+
+declare_lint_pass!(Expr2024 => [EDITION_2024_EXPR_FRAGMENT_SPECIFIER,]);
+
+impl Expr2024 {
+    fn check_tokens(&mut self, cx: &crate::EarlyContext<'_>, tokens: &TokenStream) {
+        let mut prev_colon = false;
+        let mut prev_identifier = false;
+        let mut prev_dollar = false;
+        for tt in tokens.trees() {
+            debug!(
+                "check_tokens: {:?} - colon {prev_dollar} - ident {prev_identifier} - colon {prev_colon}",
+                tt
+            );
+            match tt {
+                TokenTree::Token(token, _) => match token.kind {
+                    TokenKind::Dollar => {
+                        prev_dollar = true;
+                        continue;
+                    }
+                    TokenKind::Ident(..) | TokenKind::NtIdent(..) => {
+                        if prev_colon && prev_identifier && prev_dollar {
+                            self.check_ident_token(cx, token);
+                        } else if prev_dollar {
+                            prev_identifier = true;
+                            continue;
+                        }
+                    }
+                    TokenKind::Colon => {
+                        if prev_dollar && prev_identifier {
+                            prev_colon = true;
+                            continue;
+                        }
+                    }
+                    _ => {}
+                },
+                TokenTree::Delimited(.., tts) => self.check_tokens(cx, tts),
+            }
+            prev_colon = false;
+            prev_identifier = false;
+            prev_dollar = false;
+        }
+    }
+
+    fn check_ident_token(&mut self, cx: &crate::EarlyContext<'_>, token: &Token) {
+        debug!("check_ident_token: {:?}", token);
+        let (sym, edition) = match token.kind {
+            TokenKind::Ident(sym, _) => (sym, Edition::Edition2024),
+            _ => return,
+        };
+
+        debug!("token.span.edition(): {:?}", token.span.edition());
+        if token.span.edition() >= edition {
+            return;
+        }
+
+        if sym != sym::expr {
+            return;
+        }
+
+        debug!("emitting lint");
+        cx.builder.emit_span_lint(
+            &EDITION_2024_EXPR_FRAGMENT_SPECIFIER,
+            token.span.into(),
+            MacroExprFragment2024 { suggestion: token.span },
+        );
+    }
+}
+
+impl EarlyLintPass for Expr2024 {
+    fn check_mac_def(&mut self, cx: &crate::EarlyContext<'_>, mc: &rustc_ast::MacroDef) {
+        self.check_tokens(cx, &mc.body.tokens);
+    }
+}
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index 17429ed061f..2f8eea6cd18 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -11,10 +11,10 @@ use rustc_session::{declare_lint, impl_lint_pass};
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::Span;
 use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind, Symbol};
-use rustc_trait_selection::infer::TyCtxtInferExt;
-use rustc_trait_selection::traits::error_reporting::ambiguity::{
+use rustc_trait_selection::error_reporting::traits::ambiguity::{
     compute_applicable_impls_for_diagnostics, CandidateSource,
 };
+use rustc_trait_selection::infer::TyCtxtInferExt;
 
 use crate::fluent_generated as fluent;
 use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 91441248e70..307e4bebe9a 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -96,7 +96,9 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
             .tcx
             .normalize_erasing_regions(cx.param_env, cx.typeck_results().node_args(expr.hir_id));
         // Resolve the trait method instance.
-        let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, cx.param_env, did, args) else { return };
+        let Ok(Some(i)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, did, args) else {
+            return;
+        };
         // (Re)check that it implements the noop diagnostic.
         let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
         if !matches!(
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 8b669bcc13f..5ee73dbfdc6 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -76,9 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
         // For every projection predicate in the opaque type's explicit bounds,
         // check that the type that we're assigning actually satisfies the bounds
         // of the associated type.
-        for (pred, pred_span) in
-            cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied()
-        {
+        for (pred, pred_span) in cx.tcx.explicit_item_bounds(def_id).iter_identity_copied() {
             infcx.enter_forall(pred.kind(), |predicate| {
                 let ty::ClauseKind::Projection(proj) = predicate else {
                     return;
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 195a0f72475..65d42ed8054 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -298,9 +298,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                 ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
                     elaborate(
                         cx.tcx,
-                        cx.tcx
-                            .explicit_item_super_predicates(def)
-                            .instantiate_identity_iter_copied(),
+                        cx.tcx.explicit_item_super_predicates(def).iter_identity_copied(),
                     )
                     // We only care about self bounds for the impl-trait
                     .filter_only_self()
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 2ade6964ca8..48e20a586c6 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -80,6 +80,7 @@ declare_lint_pass! {
         PRIVATE_BOUNDS,
         PRIVATE_INTERFACES,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+        PTR_CAST_ADD_AUTO_TO_OBJECT,
         PUB_USE_OF_PRIVATE_EXTERN_CRATE,
         REDUNDANT_LIFETIMES,
         REFINING_IMPL_TRAIT_INTERNAL,
@@ -4189,6 +4190,7 @@ declare_lint! {
         reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
         reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>",
     };
+    @edition Edition2024 => Deny;
     report_in_external_macro
 }
 
@@ -4618,7 +4620,7 @@ declare_lint! {
     /// [against]: https://github.com/rust-lang/rust/issues/38831
     /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
-    Warn,
+    Deny,
     "elided lifetimes cannot be used in associated constants in impls",
     @future_incompatible = FutureIncompatibleInfo {
         reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
@@ -4938,6 +4940,58 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `ptr_cast_add_auto_to_object` lint detects casts of raw pointers to trait
+    /// objects, which add auto traits.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2021,compile_fail
+    /// let ptr: *const dyn core::any::Any = &();
+    /// _ = ptr as *const dyn core::any::Any + Send;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Adding an auto trait can make the vtable invalid, potentially causing
+    /// UB in safe code afterwards. For example:
+    ///
+    /// ```ignore (causes a warning)
+    /// #![feature(arbitrary_self_types)]
+    ///
+    /// trait Trait {
+    ///     fn f(self: *const Self)
+    ///     where
+    ///         Self: Send;
+    /// }
+    ///
+    /// impl Trait for *const () {
+    ///     fn f(self: *const Self) {
+    ///         unreachable!()
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///     let unsend: *const () = &();
+    ///     let unsend: *const dyn Trait = &unsend;
+    ///     let send_bad: *const (dyn Trait + Send) = unsend as _;
+    ///     send_bad.f(); // this crashes, since vtable for `*const ()` does not have an entry for `f`
+    /// }
+    /// ```
+    ///
+    /// Generally you must ensure that vtable is right for the pointer's type,
+    /// before passing the pointer to safe code.
+    pub PTR_CAST_ADD_AUTO_TO_OBJECT,
+    Warn,
+    "detects `as` casts from pointers to `dyn Trait` to pointers to `dyn Trait + Auto`",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
+        reference: "issue #127323 <https://github.com/rust-lang/rust/issues/127323>",
+    };
+}
+
+declare_lint! {
     /// The `out_of_scope_macro_calls` lint detects `macro_rules` called when they are not in scope,
     /// above their definition, which may happen in key-value attributes.
     ///
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index c4cfc0b6dc6..283c4fbbb7c 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -407,7 +407,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc,
     LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
     bool FunctionSections, bool DataSections, bool UniqueSectionNames,
-    bool TrapUnreachable, bool Singlethread, bool AsmComments,
+    bool TrapUnreachable, bool Singlethread, bool VerboseAsm,
     bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray,
     const char *SplitDwarfFile, const char *OutputObjFile,
     const char *DebugInfoCompression, bool UseEmulatedTls,
@@ -435,8 +435,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
   Options.DataSections = DataSections;
   Options.FunctionSections = FunctionSections;
   Options.UniqueSectionNames = UniqueSectionNames;
-  Options.MCOptions.AsmVerbose = AsmComments;
-  Options.MCOptions.PreserveAsmComments = AsmComments;
+  Options.MCOptions.AsmVerbose = VerboseAsm;
+  // Always preserve comments that were written by the user
+  Options.MCOptions.PreserveAsmComments = true;
   Options.MCOptions.ABIName = ABIStr;
   if (SplitDwarfFile) {
     Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index f4d619329eb..2b9d9a07a98 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -41,6 +41,9 @@ middle_cannot_be_normalized =
 middle_conflict_types =
     this expression supplies two conflicting concrete types for the same opaque type
 
+middle_consider_type_length_limit =
+    consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate
+
 middle_const_eval_non_int =
     constant evaluation of enum discriminant resulted in non-integer
 
@@ -94,8 +97,11 @@ middle_strict_coherence_needs_negative_coherence =
     to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
     .label = due to this attribute
 
+middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
+
 middle_unknown_layout =
     the type `{$ty}` has an unknown layout
 
 middle_values_too_big =
     values of the type `{$ty}` are too big for the current architecture
+middle_written_to_path = the full type name has been written to '{$path}'
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index 6e622b0405f..711db4e0a6b 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -1,4 +1,5 @@
 use std::fmt;
+use std::path::PathBuf;
 
 use rustc_errors::{codes::*, DiagArgName, DiagArgValue, DiagMessage};
 use rustc_macros::{Diagnostic, Subdiagnostic};
@@ -149,3 +150,16 @@ pub struct ErroneousConstant {
 
 /// Used by `rustc_const_eval`
 pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;
+
+#[derive(Diagnostic)]
+#[diag(middle_type_length_limit)]
+#[help(middle_consider_type_length_limit)]
+pub struct TypeLengthLimit {
+    #[primary_span]
+    pub span: Span,
+    pub shrunk: String,
+    #[note(middle_written_to_path)]
+    pub was_written: Option<()>,
+    pub path: PathBuf,
+    pub type_length: usize,
+}
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 305ba1ef3bb..2f3a6ee601b 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -31,9 +31,18 @@ pub struct Map<'hir> {
 
 /// An iterator that walks up the ancestor tree of a given `HirId`.
 /// Constructed using `tcx.hir().parent_iter(hir_id)`.
-pub struct ParentHirIterator<'hir> {
+struct ParentHirIterator<'hir> {
     current_id: HirId,
     map: Map<'hir>,
+    // Cache the current value of `hir_owner_nodes` to avoid repeatedly calling the same query for
+    // the same owner, which will uselessly record many times the same query dependency.
+    current_owner_nodes: Option<&'hir OwnerNodes<'hir>>,
+}
+
+impl<'hir> ParentHirIterator<'hir> {
+    fn new(map: Map<'hir>, current_id: HirId) -> ParentHirIterator<'hir> {
+        ParentHirIterator { current_id, map, current_owner_nodes: None }
+    }
 }
 
 impl<'hir> Iterator for ParentHirIterator<'hir> {
@@ -44,13 +53,22 @@ impl<'hir> Iterator for ParentHirIterator<'hir> {
             return None;
         }
 
-        // There are nodes that do not have entries, so we need to skip them.
-        let parent_id = self.map.tcx.parent_hir_id(self.current_id);
+        let HirId { owner, local_id } = self.current_id;
 
-        if parent_id == self.current_id {
-            self.current_id = CRATE_HIR_ID;
-            return None;
-        }
+        let parent_id = if local_id == ItemLocalId::ZERO {
+            // We go from an owner to its parent, so clear the cache.
+            self.current_owner_nodes = None;
+            self.map.tcx.hir_owner_parent(owner)
+        } else {
+            let owner_nodes =
+                self.current_owner_nodes.get_or_insert_with(|| self.map.tcx.hir_owner_nodes(owner));
+            let parent_local_id = owner_nodes.nodes[local_id].parent;
+            // HIR indexing should have checked that.
+            debug_assert_ne!(parent_local_id, local_id);
+            HirId { owner, local_id: parent_local_id }
+        };
+
+        debug_assert_ne!(parent_id, self.current_id);
 
         self.current_id = parent_id;
         return Some(parent_id);
@@ -479,7 +497,7 @@ impl<'hir> Map<'hir> {
     /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
     #[inline]
     pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir {
-        ParentHirIterator { current_id, map: self }
+        ParentHirIterator::new(self, current_id)
     }
 
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
diff --git a/compiler/rustc_middle/src/middle/dependency_format.rs b/compiler/rustc_middle/src/middle/dependency_format.rs
index e7d0cffc85c..a3aff9a1101 100644
--- a/compiler/rustc_middle/src/middle/dependency_format.rs
+++ b/compiler/rustc_middle/src/middle/dependency_format.rs
@@ -4,15 +4,15 @@
 //! For all the gory details, see the provider of the `dependency_formats`
 //! query.
 
+// FIXME: move this file to rustc_metadata::dependency_format, but
+// this will introduce circular dependency between rustc_metadata and rustc_middle
+
 use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_session::config::CrateType;
 
 /// A list of dependencies for a certain crate type.
 ///
 /// The length of this vector is the same as the number of external crates used.
-/// The value is None if the crate does not need to be linked (it was found
-/// statically in another dylib), or Some(kind) if it needs to be linked as
-/// `kind` (either static or dynamic).
 pub type DependencyList = Vec<Linkage>;
 
 /// A mapping of all required dependencies for a particular flavor of output.
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index e76d7af6e4a..a0c9af436e2 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -27,6 +27,10 @@ impl<'tcx> TyCtxt<'tcx> {
         self.lang_items().get(lang_item) == Some(def_id)
     }
 
+    pub fn as_lang_item(self, def_id: DefId) -> Option<LangItem> {
+        self.lang_items().from_def_id(def_id)
+    }
+
     /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits,
     /// returns a corresponding [`ty::ClosureKind`].
     /// For any other [`DefId`] return `None`.
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index 4d698012749..d0b4f36a426 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -30,7 +30,7 @@ pub fn provide(providers: &mut Providers) {
             tcx.hir().krate_attrs(),
             tcx.sess,
             sym::type_length_limit,
-            1048576,
+            2usize.pow(24),
         ),
     }
 }
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index da25fbb0a82..beaaadd497d 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -103,7 +103,7 @@ pub enum CoverageKind {
     SpanMarker,
 
     /// Marks its enclosing basic block with an ID that can be referred to by
-    /// side data in [`BranchInfo`].
+    /// side data in [`CoverageInfoHi`].
     ///
     /// Should be erased before codegen (at some point after `InstrumentCoverage`).
     BlockMarker { id: BlockMarkerId },
@@ -274,10 +274,15 @@ pub struct FunctionCoverageInfo {
     pub mcdc_num_condition_bitmaps: usize,
 }
 
-/// Branch information recorded during THIR-to-MIR lowering, and stored in MIR.
+/// Coverage information for a function, recorded during MIR building and
+/// attached to the corresponding `mir::Body`. Used by the `InstrumentCoverage`
+/// MIR pass.
+///
+/// ("Hi" indicates that this is "high-level" information collected at the
+/// THIR/MIR boundary, before the MIR-based coverage instrumentation pass.)
 #[derive(Clone, Debug)]
 #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct BranchInfo {
+pub struct CoverageInfoHi {
     /// 1 more than the highest-numbered [`CoverageKind::BlockMarker`] that was
     /// injected into the MIR body. This makes it possible to allocate per-ID
     /// data structures without having to scan the entire body first.
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 16093cfca6a..4e95e600b5a 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -18,6 +18,7 @@ use smallvec::{smallvec, SmallVec};
 use tracing::{debug, trace};
 
 use rustc_ast::LitKind;
+use rustc_attr::InlineAttr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{HashMapExt, Lock};
 use rustc_errors::ErrorGuaranteed;
@@ -134,10 +135,11 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
             AllocDiscriminant::Alloc.encode(encoder);
             alloc.encode(encoder);
         }
-        GlobalAlloc::Function(fn_instance) => {
-            trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
+        GlobalAlloc::Function { instance, unique } => {
+            trace!("encoding {:?} with {:#?}", alloc_id, instance);
             AllocDiscriminant::Fn.encode(encoder);
-            fn_instance.encode(encoder);
+            instance.encode(encoder);
+            unique.encode(encoder);
         }
         GlobalAlloc::VTable(ty, poly_trait_ref) => {
             trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id);
@@ -285,7 +287,12 @@ impl<'s> AllocDecodingSession<'s> {
                     trace!("creating fn alloc ID");
                     let instance = ty::Instance::decode(decoder);
                     trace!("decoded fn alloc instance: {:?}", instance);
-                    let alloc_id = decoder.interner().reserve_and_set_fn_alloc(instance);
+                    let unique = bool::decode(decoder);
+                    // Here we cannot call `reserve_and_set_fn_alloc` as that would use a query, which
+                    // is not possible in this context. That's why the allocation stores
+                    // whether it is unique or not.
+                    let alloc_id =
+                        decoder.interner().reserve_and_set_fn_alloc_internal(instance, unique);
                     alloc_id
                 }
                 AllocDiscriminant::VTable => {
@@ -323,7 +330,12 @@ impl<'s> AllocDecodingSession<'s> {
 #[derive(Debug, Clone, Eq, PartialEq, Hash, TyDecodable, TyEncodable, HashStable)]
 pub enum GlobalAlloc<'tcx> {
     /// The alloc ID is used as a function pointer.
-    Function(Instance<'tcx>),
+    Function {
+        instance: Instance<'tcx>,
+        /// Stores whether this instance is unique, i.e. all pointers to this function use the same
+        /// alloc ID.
+        unique: bool,
+    },
     /// This alloc ID points to a symbolic (not-reified) vtable.
     VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
     /// The alloc ID points to a "lazy" static variable that did not get computed (yet).
@@ -349,7 +361,7 @@ impl<'tcx> GlobalAlloc<'tcx> {
     #[inline]
     pub fn unwrap_fn(&self) -> Instance<'tcx> {
         match *self {
-            GlobalAlloc::Function(instance) => instance,
+            GlobalAlloc::Function { instance, .. } => instance,
             _ => bug!("expected function, got {:?}", self),
         }
     }
@@ -368,7 +380,7 @@ impl<'tcx> GlobalAlloc<'tcx> {
     #[inline]
     pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace {
         match self {
-            GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
+            GlobalAlloc::Function { .. } => cx.data_layout().instruction_address_space,
             GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
                 AddressSpace::DATA
             }
@@ -426,7 +438,7 @@ impl<'tcx> TyCtxt<'tcx> {
     fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId {
         let mut alloc_map = self.alloc_map.lock();
         match alloc {
-            GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {}
+            GlobalAlloc::Function { .. } | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {}
             GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"),
         }
         if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) {
@@ -445,30 +457,45 @@ impl<'tcx> TyCtxt<'tcx> {
         self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
     }
 
+    /// Generates an `AllocId` for a function. The caller must already have decided whether this
+    /// function obtains a unique AllocId or gets de-duplicated via the cache.
+    fn reserve_and_set_fn_alloc_internal(self, instance: Instance<'tcx>, unique: bool) -> AllocId {
+        let alloc = GlobalAlloc::Function { instance, unique };
+        if unique {
+            // Deduplicate.
+            self.reserve_and_set_dedup(alloc)
+        } else {
+            // Get a fresh ID.
+            let mut alloc_map = self.alloc_map.lock();
+            let id = alloc_map.reserve();
+            alloc_map.alloc_map.insert(id, alloc);
+            id
+        }
+    }
+
     /// Generates an `AllocId` for a function. Depending on the function type,
     /// this might get deduplicated or assigned a new ID each time.
     pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
         // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
         // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
-        // duplicated across crates.
-        // We thus generate a new `AllocId` for every mention of a function. This means that
-        // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
-        // However, formatting code relies on function identity (see #58320), so we only do
-        // this for generic functions. Lifetime parameters are ignored.
+        // duplicated across crates. We thus generate a new `AllocId` for every mention of a
+        // function. This means that `main as fn() == main as fn()` is false, while `let x = main as
+        // fn(); x == x` is true. However, as a quality-of-life feature it can be useful to identify
+        // certain functions uniquely, e.g. for backtraces. So we identify whether codegen will
+        // actually emit duplicate functions. It does that when they have non-lifetime generics, or
+        // when they can be inlined. All other functions are given a unique address.
+        // This is not a stable guarantee! The `inline` attribute is a hint and cannot be relied
+        // upon for anything. But if we don't do this, backtraces look terrible.
         let is_generic = instance
             .args
             .into_iter()
             .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
-        if is_generic {
-            // Get a fresh ID.
-            let mut alloc_map = self.alloc_map.lock();
-            let id = alloc_map.reserve();
-            alloc_map.alloc_map.insert(id, GlobalAlloc::Function(instance));
-            id
-        } else {
-            // Deduplicate.
-            self.reserve_and_set_dedup(GlobalAlloc::Function(instance))
-        }
+        let can_be_inlined = match self.codegen_fn_attrs(instance.def_id()).inline {
+            InlineAttr::Never => false,
+            _ => true,
+        };
+        let unique = !is_generic && !can_be_inlined;
+        self.reserve_and_set_fn_alloc_internal(instance, unique)
     }
 
     /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 95857e8579d..96613592bbc 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -73,7 +73,7 @@ impl<'tcx> TyCtxt<'tcx> {
             bug!("did not expect inference variables here");
         }
 
-        match ty::Instance::resolve(
+        match ty::Instance::try_resolve(
             self, param_env,
             // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst?
             ct.def, ct.args,
@@ -106,7 +106,7 @@ impl<'tcx> TyCtxt<'tcx> {
             bug!("did not expect inference variables here");
         }
 
-        match ty::Instance::resolve(self, param_env, ct.def, ct.args) {
+        match ty::Instance::try_resolve(self, param_env, ct.def, ct.args) {
             Ok(Some(instance)) => {
                 let cid = GlobalId { instance, promoted: None };
                 self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index ef88b253864..83e3898cebf 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -430,11 +430,12 @@ pub struct Body<'tcx> {
 
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 
-    /// Branch coverage information collected during MIR building, to be used by
-    /// the `InstrumentCoverage` pass.
+    /// Coverage information collected from THIR/MIR during MIR building,
+    /// to be used by the `InstrumentCoverage` pass.
     ///
-    /// Only present if branch coverage is enabled and this function is eligible.
-    pub coverage_branch_info: Option<Box<coverage::BranchInfo>>,
+    /// Only present if coverage is enabled and this function is eligible.
+    /// Boxed to limit space overhead in non-coverage builds.
+    pub coverage_info_hi: Option<Box<coverage::CoverageInfoHi>>,
 
     /// Per-function coverage information added by the `InstrumentCoverage`
     /// pass, to be used in conjunction with the coverage statements injected
@@ -484,7 +485,7 @@ impl<'tcx> Body<'tcx> {
             is_polymorphic: false,
             injection_phase: None,
             tainted_by_errors,
-            coverage_branch_info: None,
+            coverage_info_hi: None,
             function_coverage_info: None,
         };
         body.is_polymorphic = body.has_non_region_param();
@@ -515,7 +516,7 @@ impl<'tcx> Body<'tcx> {
             is_polymorphic: false,
             injection_phase: None,
             tainted_by_errors: None,
-            coverage_branch_info: None,
+            coverage_info_hi: None,
             function_coverage_info: None,
         };
         body.is_polymorphic = body.has_non_region_param();
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 4657f4dcf81..82625ae3d47 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -473,8 +473,8 @@ pub fn write_mir_intro<'tcx>(
     // Add an empty line before the first block is printed.
     writeln!(w)?;
 
-    if let Some(branch_info) = &body.coverage_branch_info {
-        write_coverage_branch_info(branch_info, w)?;
+    if let Some(coverage_info_hi) = &body.coverage_info_hi {
+        write_coverage_info_hi(coverage_info_hi, w)?;
     }
     if let Some(function_coverage_info) = &body.function_coverage_info {
         write_function_coverage_info(function_coverage_info, w)?;
@@ -483,18 +483,26 @@ pub fn write_mir_intro<'tcx>(
     Ok(())
 }
 
-fn write_coverage_branch_info(
-    branch_info: &coverage::BranchInfo,
+fn write_coverage_info_hi(
+    coverage_info_hi: &coverage::CoverageInfoHi,
     w: &mut dyn io::Write,
 ) -> io::Result<()> {
-    let coverage::BranchInfo { branch_spans, mcdc_branch_spans, mcdc_decision_spans, .. } =
-        branch_info;
+    let coverage::CoverageInfoHi {
+        num_block_markers: _,
+        branch_spans,
+        mcdc_branch_spans,
+        mcdc_decision_spans,
+    } = coverage_info_hi;
+
+    // Only add an extra trailing newline if we printed at least one thing.
+    let mut did_print = false;
 
     for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans {
         writeln!(
             w,
             "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
         )?;
+        did_print = true;
     }
 
     for coverage::MCDCBranchSpan {
@@ -510,6 +518,7 @@ fn write_coverage_branch_info(
             "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?}, depth: {decision_depth:?} }} => {span:?}",
             condition_info.map(|info| info.condition_id)
         )?;
+        did_print = true;
     }
 
     for coverage::MCDCDecisionSpan { span, num_conditions, end_markers, decision_depth } in
@@ -519,10 +528,10 @@ fn write_coverage_branch_info(
             w,
             "{INDENT}coverage mcdc decision {{ num_conditions: {num_conditions:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}"
         )?;
+        did_print = true;
     }
 
-    if !branch_spans.is_empty() || !mcdc_branch_spans.is_empty() || !mcdc_decision_spans.is_empty()
-    {
+    if did_print {
         writeln!(w)?;
     }
 
@@ -845,6 +854,16 @@ impl<'tcx> TerminatorKind<'tcx> {
                 }
                 write!(fmt, ")")
             }
+            TailCall { func, args, .. } => {
+                write!(fmt, "tailcall {func:?}(")?;
+                for (index, arg) in args.iter().enumerate() {
+                    if index > 0 {
+                        write!(fmt, ", ")?;
+                    }
+                    write!(fmt, "{:?}", arg)?;
+                }
+                write!(fmt, ")")
+            }
             Assert { cond, expected, msg, .. } => {
                 write!(fmt, "assert(")?;
                 if !expected {
@@ -912,7 +931,12 @@ impl<'tcx> TerminatorKind<'tcx> {
     pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
         use self::TerminatorKind::*;
         match *self {
-            Return | UnwindResume | UnwindTerminate(_) | Unreachable | CoroutineDrop => vec![],
+            Return
+            | TailCall { .. }
+            | UnwindResume
+            | UnwindTerminate(_)
+            | Unreachable
+            | CoroutineDrop => vec![],
             Goto { .. } => vec!["".into()],
             SwitchInt { ref targets, .. } => targets
                 .values
@@ -1449,7 +1473,7 @@ pub fn write_allocations<'tcx>(
             // This can't really happen unless there are bugs, but it doesn't cost us anything to
             // gracefully handle it and allow buggy rustc to be debugged via allocation printing.
             None => write!(w, " (deallocated)")?,
-            Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?,
+            Some(GlobalAlloc::Function { instance, .. }) => write!(w, " (fn: {instance})")?,
             Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => {
                 write!(w, " (vtable: impl {trait_ref} for {ty})")?
             }
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 46b38e4a6a6..cd8e28522ec 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -274,6 +274,9 @@ pub enum ConstraintCategory<'tcx> {
 
     /// A constraint that doesn't correspond to anything the user sees.
     Internal,
+
+    /// An internal constraint derived from an illegal universe relation.
+    IllegalUniverse,
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 2c2884f1897..620fa962d79 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -744,6 +744,36 @@ pub enum TerminatorKind<'tcx> {
         fn_span: Span,
     },
 
+    /// Tail call.
+    ///
+    /// Roughly speaking this is a chimera of [`Call`] and [`Return`], with some caveats.
+    /// Semantically tail calls consists of two actions:
+    /// - pop of the current stack frame
+    /// - a call to the `func`, with the return address of the **current** caller
+    ///   - so that a `return` inside `func` returns to the caller of the caller
+    ///     of the function that is currently being executed
+    ///
+    /// Note that in difference with [`Call`] this is missing
+    /// - `destination` (because it's always the return place)
+    /// - `target` (because it's always taken from the current stack frame)
+    /// - `unwind` (because it's always taken from the current stack frame)
+    ///
+    /// [`Call`]: TerminatorKind::Call
+    /// [`Return`]: TerminatorKind::Return
+    TailCall {
+        /// The function that’s being called.
+        func: Operand<'tcx>,
+        /// Arguments the function is called with.
+        /// These are owned by the callee, which is free to modify them.
+        /// This allows the memory occupied by "by-value" arguments to be
+        /// reused across function calls without duplicating the contents.
+        args: Box<[Spanned<Operand<'tcx>>]>,
+        // FIXME(explicit_tail_calls): should we have the span for `become`? is this span accurate? do we need it?
+        /// This `Span` is the span of the function, without the dot and receiver
+        /// (e.g. `foo(a, b)` in `x.foo(a, b)`
+        fn_span: Span,
+    },
+
     /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`,
     /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some
     /// unspecified constant as the function to call, all the operands stored in the `AssertMessage`
@@ -870,6 +900,7 @@ impl TerminatorKind<'_> {
             TerminatorKind::Unreachable => "Unreachable",
             TerminatorKind::Drop { .. } => "Drop",
             TerminatorKind::Call { .. } => "Call",
+            TerminatorKind::TailCall { .. } => "TailCall",
             TerminatorKind::Assert { .. } => "Assert",
             TerminatorKind::Yield { .. } => "Yield",
             TerminatorKind::CoroutineDrop => "CoroutineDrop",
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index ed592612358..5b035d9579d 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -439,6 +439,7 @@ mod helper {
                 | CoroutineDrop
                 | Return
                 | Unreachable
+                | TailCall { .. }
                 | Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
                 InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
                     targets.iter().copied().chain(Some(u))
@@ -479,6 +480,7 @@ mod helper {
                 | CoroutineDrop
                 | Return
                 | Unreachable
+                | TailCall { .. }
                 | Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
                 InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
                     targets.iter_mut().chain(Some(u))
@@ -501,6 +503,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             | TerminatorKind::UnwindResume
             | TerminatorKind::UnwindTerminate(_)
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::Unreachable
             | TerminatorKind::CoroutineDrop
             | TerminatorKind::Yield { .. }
@@ -521,6 +524,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             | TerminatorKind::UnwindResume
             | TerminatorKind::UnwindTerminate(_)
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::Unreachable
             | TerminatorKind::CoroutineDrop
             | TerminatorKind::Yield { .. }
@@ -606,9 +610,12 @@ impl<'tcx> TerminatorKind<'tcx> {
     pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
         use TerminatorKind::*;
         match *self {
-            Return | UnwindResume | UnwindTerminate(_) | CoroutineDrop | Unreachable => {
-                TerminatorEdges::None
-            }
+            Return
+            | TailCall { .. }
+            | UnwindResume
+            | UnwindTerminate(_)
+            | CoroutineDrop
+            | Unreachable => TerminatorEdges::None,
 
             Goto { target } => TerminatorEdges::Single(target),
 
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 7628a1ed2fe..0d3c419748b 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -540,6 +540,17 @@ macro_rules! make_mir_visitor {
                         );
                     }
 
+                    TerminatorKind::TailCall {
+                        func,
+                        args,
+                        fn_span: _,
+                    } => {
+                        self.visit_operand(func, location);
+                        for arg in args {
+                            self.visit_operand(&$($mutability)? arg.node, location);
+                        }
+                    },
+
                     TerminatorKind::Assert {
                         cond,
                         expected: _,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d40a7833589..33c27d41d86 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2197,8 +2197,8 @@ rustc_queries! {
     ///  * `Err(ErrorGuaranteed)` when the `Instance` resolution process
     ///    couldn't complete due to errors elsewhere - this is distinct
     ///    from `Ok(None)` to avoid misleading diagnostics when an error
-    ///    has already been/will be emitted, for the original cause
-    query resolve_instance(
+    ///    has already been/will be emitted, for the original cause.
+    query resolve_instance_raw(
         key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>
     ) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
         desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index b4e3fae1b43..b74775142e4 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -7,7 +7,6 @@ pub mod select;
 pub mod solve;
 pub mod specialization_graph;
 mod structural_impls;
-pub mod util;
 
 use crate::mir::ConstraintCategory;
 use crate::ty::abstract_const::NotConstEvaluatable;
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
deleted file mode 100644
index 7437be7a74c..00000000000
--- a/compiler/rustc_middle/src/traits/util.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use rustc_data_structures::fx::FxHashSet;
-
-use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, TyCtxt, Upcast};
-
-/// Given a [`PolyTraitRef`], get the [`Clause`]s implied by the trait's definition.
-///
-/// This only exists in `rustc_middle` because the more powerful elaborator depends on
-/// `rustc_infer` for elaborating outlives bounds -- this should only be used for pretty
-/// printing.
-pub fn super_predicates_for_pretty_printing<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: PolyTraitRef<'tcx>,
-) -> impl Iterator<Item = Clause<'tcx>> {
-    let clause = trait_ref.upcast(tcx);
-    Elaborator { tcx, visited: FxHashSet::from_iter([clause]), stack: vec![clause] }
-}
-
-/// Like [`super_predicates_for_pretty_printing`], except it only returns traits and filters out
-/// all other [`Clause`]s.
-pub fn supertraits_for_pretty_printing<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: PolyTraitRef<'tcx>,
-) -> impl Iterator<Item = PolyTraitRef<'tcx>> {
-    super_predicates_for_pretty_printing(tcx, trait_ref).filter_map(|clause| {
-        clause.as_trait_clause().map(|trait_clause| trait_clause.to_poly_trait_ref())
-    })
-}
-
-struct Elaborator<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    visited: FxHashSet<Clause<'tcx>>,
-    stack: Vec<Clause<'tcx>>,
-}
-
-impl<'tcx> Elaborator<'tcx> {
-    fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) {
-        let super_predicates =
-            self.tcx.explicit_super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map(
-                |&(pred, _)| {
-                    let clause = pred.instantiate_supertrait(self.tcx, trait_ref);
-                    self.visited.insert(clause).then_some(clause)
-                },
-            );
-
-        self.stack.extend(super_predicates);
-    }
-}
-
-impl<'tcx> Iterator for Elaborator<'tcx> {
-    type Item = Clause<'tcx>;
-
-    fn next(&mut self) -> Option<Clause<'tcx>> {
-        if let Some(clause) = self.stack.pop() {
-            if let Some(trait_clause) = clause.as_trait_clause() {
-                self.elaborate(trait_clause.to_poly_trait_ref());
-            }
-            Some(clause)
-        } else {
-            None
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 8e221cdc603..88ee32eae95 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -229,6 +229,10 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
     fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
         self.sized_constraint(tcx)
     }
+
+    fn is_fundamental(self) -> bool {
+        self.is_fundamental()
+    }
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index bade0d56415..bdd9a6bab2b 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -237,7 +237,7 @@ impl<'tcx> TyCtxt<'tcx> {
 /// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of
 ///        `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`.
 ///        Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`.
-///     2. Since we only look at the projections here function will return `bar.x` as an a valid
+///     2. Since we only look at the projections here function will return `bar.x` as a valid
 ///        ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
 ///        list are being applied to the same root variable.
 pub fn is_ancestor_or_same_capture(
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index bf834ef7607..98f35b6b8ab 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -54,6 +54,13 @@ pub struct Expr<'tcx> {
     pub kind: ExprKind,
     args: ty::GenericArgsRef<'tcx>,
 }
+
+impl<'tcx> rustc_type_ir::inherent::ExprConst<TyCtxt<'tcx>> for Expr<'tcx> {
+    fn args(self) -> ty::GenericArgsRef<'tcx> {
+        self.args
+    }
+}
+
 impl<'tcx> Expr<'tcx> {
     pub fn new_binop(
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 9225ae6300f..aee42bfe3aa 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -37,7 +37,7 @@ use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use rustc_ast::{self as ast, attr};
 use rustc_data_structures::defer;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
@@ -92,6 +92,8 @@ use std::ops::{Bound, Deref};
 impl<'tcx> Interner for TyCtxt<'tcx> {
     type DefId = DefId;
     type LocalDefId = LocalDefId;
+    type Span = Span;
+
     type GenericArgs = ty::GenericArgsRef<'tcx>;
 
     type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
@@ -345,12 +347,16 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     fn explicit_super_predicates_of(
         self,
         def_id: DefId,
-    ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
+    ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>> {
+        ty::EarlyBinder::bind(self.explicit_super_predicates_of(def_id).instantiate_identity(self))
+    }
+
+    fn explicit_implied_predicates_of(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>> {
         ty::EarlyBinder::bind(
-            self.explicit_super_predicates_of(def_id)
-                .instantiate_identity(self)
-                .predicates
-                .into_iter(),
+            self.explicit_implied_predicates_of(def_id).instantiate_identity(self),
         )
     }
 
@@ -366,6 +372,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item))
     }
 
+    fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
+        lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?)
+    }
+
     fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
         self.associated_items(def_id)
             .in_definition_order()
@@ -373,17 +383,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
             .map(|assoc_item| assoc_item.def_id)
     }
 
-    fn args_may_unify_deep(
-        self,
-        obligation_args: ty::GenericArgsRef<'tcx>,
-        impl_args: ty::GenericArgsRef<'tcx>,
-    ) -> bool {
-        ty::fast_reject::DeepRejectCtxt {
-            treat_obligation_params: ty::fast_reject::TreatParams::ForLookup,
-        }
-        .args_may_unify(obligation_args, impl_args)
-    }
-
     // This implementation is a bit different from `TyCtxt::for_each_relevant_impl`,
     // since we want to skip over blanket impls for non-rigid aliases, and also we
     // only want to consider types that *actually* unify with float/int vars.
@@ -529,20 +528,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.is_object_safe(trait_def_id)
     }
 
-    fn trait_may_be_implemented_via_object(self, trait_def_id: DefId) -> bool {
-        self.trait_def(trait_def_id).implement_via_object
-    }
-
-    fn fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option<ty::ClosureKind> {
-        self.fn_trait_kind_from_def_id(trait_def_id)
-    }
-
-    fn async_fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option<ty::ClosureKind> {
-        self.async_fn_trait_kind_from_def_id(trait_def_id)
+    fn trait_is_fundamental(self, def_id: DefId) -> bool {
+        self.trait_def(def_id).is_fundamental
     }
 
-    fn supertrait_def_ids(self, trait_def_id: DefId) -> impl IntoIterator<Item = DefId> {
-        self.supertrait_def_ids(trait_def_id)
+    fn trait_may_be_implemented_via_object(self, trait_def_id: DefId) -> bool {
+        self.trait_def(trait_def_id).implement_via_object
     }
 
     fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed {
@@ -582,49 +573,83 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     ) -> Ty<'tcx> {
         placeholder.find_const_ty_from_env(param_env)
     }
+
+    fn anonymize_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
+        self,
+        binder: ty::Binder<'tcx, T>,
+    ) -> ty::Binder<'tcx, T> {
+        self.anonymize_bound_vars(binder)
+    }
 }
 
-fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem {
-    match lang_item {
-        TraitSolverLangItem::AsyncDestruct => LangItem::AsyncDestruct,
-        TraitSolverLangItem::AsyncFnKindHelper => LangItem::AsyncFnKindHelper,
-        TraitSolverLangItem::AsyncFnKindUpvars => LangItem::AsyncFnKindUpvars,
-        TraitSolverLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput,
-        TraitSolverLangItem::AsyncIterator => LangItem::AsyncIterator,
-        TraitSolverLangItem::CallOnceFuture => LangItem::CallOnceFuture,
-        TraitSolverLangItem::CallRefFuture => LangItem::CallRefFuture,
-        TraitSolverLangItem::Clone => LangItem::Clone,
-        TraitSolverLangItem::Copy => LangItem::Copy,
-        TraitSolverLangItem::Coroutine => LangItem::Coroutine,
-        TraitSolverLangItem::CoroutineReturn => LangItem::CoroutineReturn,
-        TraitSolverLangItem::CoroutineYield => LangItem::CoroutineYield,
-        TraitSolverLangItem::Destruct => LangItem::Destruct,
-        TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind,
-        TraitSolverLangItem::DynMetadata => LangItem::DynMetadata,
-        TraitSolverLangItem::EffectsMaybe => LangItem::EffectsMaybe,
-        TraitSolverLangItem::EffectsIntersection => LangItem::EffectsIntersection,
-        TraitSolverLangItem::EffectsIntersectionOutput => LangItem::EffectsIntersectionOutput,
-        TraitSolverLangItem::EffectsNoRuntime => LangItem::EffectsNoRuntime,
-        TraitSolverLangItem::EffectsRuntime => LangItem::EffectsRuntime,
-        TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait,
-        TraitSolverLangItem::FusedIterator => LangItem::FusedIterator,
-        TraitSolverLangItem::Future => LangItem::Future,
-        TraitSolverLangItem::FutureOutput => LangItem::FutureOutput,
-        TraitSolverLangItem::Iterator => LangItem::Iterator,
-        TraitSolverLangItem::Metadata => LangItem::Metadata,
-        TraitSolverLangItem::Option => LangItem::Option,
-        TraitSolverLangItem::PointeeTrait => LangItem::PointeeTrait,
-        TraitSolverLangItem::PointerLike => LangItem::PointerLike,
-        TraitSolverLangItem::Poll => LangItem::Poll,
-        TraitSolverLangItem::Sized => LangItem::Sized,
-        TraitSolverLangItem::TransmuteTrait => LangItem::TransmuteTrait,
-        TraitSolverLangItem::Tuple => LangItem::Tuple,
-        TraitSolverLangItem::Unpin => LangItem::Unpin,
-        TraitSolverLangItem::Unsize => LangItem::Unsize,
+macro_rules! bidirectional_lang_item_map {
+    ($($name:ident),+ $(,)?) => {
+        fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem {
+            match lang_item {
+                $(TraitSolverLangItem::$name => LangItem::$name,)+
+            }
+        }
+
+        fn lang_item_to_trait_lang_item(lang_item: LangItem) -> Option<TraitSolverLangItem> {
+            Some(match lang_item {
+                $(LangItem::$name => TraitSolverLangItem::$name,)+
+                _ => return None,
+            })
+        }
     }
 }
 
+bidirectional_lang_item_map! {
+// tidy-alphabetical-start
+    AsyncDestruct,
+    AsyncFn,
+    AsyncFnKindHelper,
+    AsyncFnKindUpvars,
+    AsyncFnMut,
+    AsyncFnOnce,
+    AsyncFnOnceOutput,
+    AsyncIterator,
+    CallOnceFuture,
+    CallRefFuture,
+    Clone,
+    Copy,
+    Coroutine,
+    CoroutineReturn,
+    CoroutineYield,
+    Destruct,
+    DiscriminantKind,
+    DynMetadata,
+    EffectsIntersection,
+    EffectsIntersectionOutput,
+    EffectsMaybe,
+    EffectsNoRuntime,
+    EffectsRuntime,
+    Fn,
+    FnMut,
+    FnOnce,
+    FnPtrTrait,
+    FusedIterator,
+    Future,
+    FutureOutput,
+    Iterator,
+    Metadata,
+    Option,
+    PointeeTrait,
+    PointerLike,
+    Poll,
+    Sized,
+    TransmuteTrait,
+    Tuple,
+    Unpin,
+    Unsize,
+// tidy-alphabetical-end
+}
+
 impl<'tcx> rustc_type_ir::inherent::DefId<TyCtxt<'tcx>> for DefId {
+    fn is_local(self) -> bool {
+        self.is_local()
+    }
+
     fn as_local(self) -> Option<LocalDefId> {
         self.as_local()
     }
@@ -2474,25 +2499,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// to identify which traits may define a given associated type to help avoid cycle errors,
     /// and to make size estimates for vtable layout computation.
     pub fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
-        let mut set = FxHashSet::default();
-        let mut stack = vec![trait_def_id];
-
-        set.insert(trait_def_id);
-
-        iter::from_fn(move || -> Option<DefId> {
-            let trait_did = stack.pop()?;
-            let generic_predicates = self.explicit_super_predicates_of(trait_did);
-
-            for (predicate, _) in generic_predicates.predicates {
-                if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() {
-                    if set.insert(data.def_id()) {
-                        stack.push(data.def_id());
-                    }
-                }
-            }
-
-            Some(trait_did)
-        })
+        rustc_type_ir::elaborate::supertrait_def_ids(self, trait_def_id)
     }
 
     /// Given a closure signature, returns an equivalent fn signature. Detuples
diff --git a/compiler/rustc_middle/src/ty/elaborate_impl.rs b/compiler/rustc_middle/src/ty/elaborate_impl.rs
new file mode 100644
index 00000000000..8c89a2d884b
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/elaborate_impl.rs
@@ -0,0 +1,84 @@
+use rustc_span::Span;
+use rustc_type_ir::elaborate::Elaboratable;
+
+use crate::ty::{self, TyCtxt};
+
+impl<'tcx> Elaboratable<TyCtxt<'tcx>> for ty::Clause<'tcx> {
+    fn predicate(&self) -> ty::Predicate<'tcx> {
+        self.as_predicate()
+    }
+
+    fn child(&self, clause: ty::Clause<'tcx>) -> Self {
+        clause
+    }
+
+    fn child_with_derived_cause(
+        &self,
+        clause: ty::Clause<'tcx>,
+        _span: Span,
+        _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        _index: usize,
+    ) -> Self {
+        clause
+    }
+}
+
+impl<'tcx> Elaboratable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
+    fn predicate(&self) -> ty::Predicate<'tcx> {
+        *self
+    }
+
+    fn child(&self, clause: ty::Clause<'tcx>) -> Self {
+        clause.as_predicate()
+    }
+
+    fn child_with_derived_cause(
+        &self,
+        clause: ty::Clause<'tcx>,
+        _span: Span,
+        _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        _index: usize,
+    ) -> Self {
+        clause.as_predicate()
+    }
+}
+
+impl<'tcx> Elaboratable<TyCtxt<'tcx>> for (ty::Predicate<'tcx>, Span) {
+    fn predicate(&self) -> ty::Predicate<'tcx> {
+        self.0
+    }
+
+    fn child(&self, clause: ty::Clause<'tcx>) -> Self {
+        (clause.as_predicate(), self.1)
+    }
+
+    fn child_with_derived_cause(
+        &self,
+        clause: ty::Clause<'tcx>,
+        _span: Span,
+        _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        _index: usize,
+    ) -> Self {
+        (clause.as_predicate(), self.1)
+    }
+}
+
+impl<'tcx> Elaboratable<TyCtxt<'tcx>> for (ty::Clause<'tcx>, Span) {
+    fn predicate(&self) -> ty::Predicate<'tcx> {
+        self.0.as_predicate()
+    }
+
+    fn child(&self, clause: ty::Clause<'tcx>) -> Self {
+        (clause, self.1)
+    }
+
+    fn child_with_derived_cause(
+        &self,
+        clause: ty::Clause<'tcx>,
+        _span: Span,
+        _parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        _index: usize,
+    ) -> Self {
+        (clause, self.1)
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 923667e609b..0413cfa5a63 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -1,369 +1,9 @@
-use crate::mir::Mutability;
-use crate::ty::GenericArgKind;
-use crate::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
 use rustc_hir::def_id::DefId;
-use rustc_macros::{HashStable, TyDecodable, TyEncodable};
-use std::fmt::Debug;
-use std::hash::Hash;
-use std::iter;
 
-/// See `simplify_type`.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
-pub enum SimplifiedType {
-    Bool,
-    Char,
-    Int(ty::IntTy),
-    Uint(ty::UintTy),
-    Float(ty::FloatTy),
-    Adt(DefId),
-    Foreign(DefId),
-    Str,
-    Array,
-    Slice,
-    Ref(Mutability),
-    Ptr(Mutability),
-    Never,
-    Tuple(usize),
-    /// A trait object, all of whose components are markers
-    /// (e.g., `dyn Send + Sync`).
-    MarkerTraitObject,
-    Trait(DefId),
-    Closure(DefId),
-    Coroutine(DefId),
-    CoroutineWitness(DefId),
-    Function(usize),
-    Placeholder,
-    Error,
-}
+use super::TyCtxt;
 
-/// Generic parameters are pretty much just bound variables, e.g.
-/// the type of `fn foo<'a, T>(x: &'a T) -> u32 { ... }` can be thought of as
-/// `for<'a, T> fn(&'a T) -> u32`.
-///
-/// Typecheck of `foo` has to succeed for all possible generic arguments, so
-/// during typeck, we have to treat its generic parameters as if they
-/// were placeholders.
-///
-/// But when calling `foo` we only have to provide a specific generic argument.
-/// In that case the generic parameters are instantiated with inference variables.
-/// As we use `simplify_type` before that instantiation happens, we just treat
-/// generic parameters as if they were inference variables in that case.
-#[derive(PartialEq, Eq, Debug, Clone, Copy)]
-pub enum TreatParams {
-    /// Treat parameters as infer vars. This is the correct mode for caching
-    /// an impl's type for lookup.
-    AsCandidateKey,
-    /// Treat parameters as placeholders in the given environment. This is the
-    /// correct mode for *lookup*, as during candidate selection.
-    ///
-    /// This also treats projections with inference variables as infer vars
-    /// since they could be further normalized.
-    ForLookup,
-}
+pub use rustc_type_ir::fast_reject::*;
 
-/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
-///
-/// **This function should only be used if you need to store or retrieve the type from some
-/// hashmap. If you want to quickly decide whether two types may unify, use the [DeepRejectCtxt]
-/// instead.**
-///
-/// The idea is to get something simple that we can use to quickly decide if two types could unify,
-/// for example during method lookup. If this function returns `Some(x)` it can only unify with
-/// types for which this method returns either `Some(x)` as well or `None`.
-///
-/// A special case here are parameters and projections, which are only injective
-/// if they are treated as placeholders.
-///
-/// For example when storing impls based on their simplified self type, we treat
-/// generic parameters as if they were inference variables. We must not simplify them here,
-/// as they can unify with any other type.
-///
-/// With projections we have to be even more careful, as treating them as placeholders
-/// is only correct if they are fully normalized.
-///
-/// ¹ meaning that if the outermost layers are different, then the whole types are also different.
-pub fn simplify_type<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-    treat_params: TreatParams,
-) -> Option<SimplifiedType> {
-    match *ty.kind() {
-        ty::Bool => Some(SimplifiedType::Bool),
-        ty::Char => Some(SimplifiedType::Char),
-        ty::Int(int_type) => Some(SimplifiedType::Int(int_type)),
-        ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)),
-        ty::Float(float_type) => Some(SimplifiedType::Float(float_type)),
-        ty::Adt(def, _) => Some(SimplifiedType::Adt(def.did())),
-        ty::Str => Some(SimplifiedType::Str),
-        ty::Array(..) => Some(SimplifiedType::Array),
-        ty::Slice(..) => Some(SimplifiedType::Slice),
-        ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params),
-        ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)),
-        ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
-            Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
-                Some(SimplifiedType::Trait(principal_def_id))
-            }
-            _ => Some(SimplifiedType::MarkerTraitObject),
-        },
-        ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
-        ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => {
-            Some(SimplifiedType::Closure(def_id))
-        }
-        ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)),
-        ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)),
-        ty::Never => Some(SimplifiedType::Never),
-        ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
-        ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())),
-        ty::Placeholder(..) => Some(SimplifiedType::Placeholder),
-        ty::Param(_) => match treat_params {
-            TreatParams::ForLookup => Some(SimplifiedType::Placeholder),
-            TreatParams::AsCandidateKey => None,
-        },
-        ty::Alias(..) => match treat_params {
-            // When treating `ty::Param` as a placeholder, projections also
-            // don't unify with anything else as long as they are fully normalized.
-            // FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder`
-            // when the new solver is enabled by default.
-            TreatParams::ForLookup if !ty.has_non_region_infer() => {
-                Some(SimplifiedType::Placeholder)
-            }
-            TreatParams::ForLookup | TreatParams::AsCandidateKey => None,
-        },
-        ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)),
-        ty::Error(_) => Some(SimplifiedType::Error),
-        ty::Bound(..) | ty::Infer(_) => None,
-    }
-}
+pub type DeepRejectCtxt<'tcx> = rustc_type_ir::fast_reject::DeepRejectCtxt<TyCtxt<'tcx>>;
 
-impl SimplifiedType {
-    pub fn def(self) -> Option<DefId> {
-        match self {
-            SimplifiedType::Adt(d)
-            | SimplifiedType::Foreign(d)
-            | SimplifiedType::Trait(d)
-            | SimplifiedType::Closure(d)
-            | SimplifiedType::Coroutine(d)
-            | SimplifiedType::CoroutineWitness(d) => Some(d),
-            _ => None,
-        }
-    }
-}
-
-/// Given generic arguments from an obligation and an impl,
-/// could these two be unified after replacing parameters in the
-/// the impl with inference variables.
-///
-/// For obligations, parameters won't be replaced by inference
-/// variables and only unify with themselves. We treat them
-/// the same way we treat placeholders.
-///
-/// We also use this function during coherence. For coherence the
-/// impls only have to overlap for some value, so we treat parameters
-/// on both sides like inference variables. This behavior is toggled
-/// using the `treat_obligation_params` field.
-#[derive(Debug, Clone, Copy)]
-pub struct DeepRejectCtxt {
-    pub treat_obligation_params: TreatParams,
-}
-
-impl DeepRejectCtxt {
-    pub fn args_may_unify<'tcx>(
-        self,
-        obligation_args: GenericArgsRef<'tcx>,
-        impl_args: GenericArgsRef<'tcx>,
-    ) -> bool {
-        iter::zip(obligation_args, impl_args).all(|(obl, imp)| {
-            match (obl.unpack(), imp.unpack()) {
-                // We don't fast reject based on regions.
-                (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true,
-                (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => {
-                    self.types_may_unify(obl, imp)
-                }
-                (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => {
-                    self.consts_may_unify(obl, imp)
-                }
-                _ => bug!("kind mismatch: {obl} {imp}"),
-            }
-        })
-    }
-
-    pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool {
-        match impl_ty.kind() {
-            // Start by checking whether the type in the impl may unify with
-            // pretty much everything. Just return `true` in that case.
-            ty::Param(_) | ty::Error(_) | ty::Alias(..) => return true,
-            // These types only unify with inference variables or their own
-            // variant.
-            ty::Bool
-            | ty::Char
-            | ty::Int(_)
-            | ty::Uint(_)
-            | ty::Float(_)
-            | ty::Adt(..)
-            | ty::Str
-            | ty::Array(..)
-            | ty::Slice(..)
-            | ty::RawPtr(..)
-            | ty::Dynamic(..)
-            | ty::Pat(..)
-            | ty::Ref(..)
-            | ty::Never
-            | ty::Tuple(..)
-            | ty::FnPtr(..)
-            | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()),
-            ty::FnDef(..)
-            | ty::Closure(..)
-            | ty::CoroutineClosure(..)
-            | ty::Coroutine(..)
-            | ty::CoroutineWitness(..)
-            | ty::Placeholder(..)
-            | ty::Bound(..)
-            | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"),
-        }
-
-        let k = impl_ty.kind();
-        match *obligation_ty.kind() {
-            // Purely rigid types, use structural equivalence.
-            ty::Bool
-            | ty::Char
-            | ty::Int(_)
-            | ty::Uint(_)
-            | ty::Float(_)
-            | ty::Str
-            | ty::Never
-            | ty::Foreign(_) => obligation_ty == impl_ty,
-            ty::Ref(_, obl_ty, obl_mutbl) => match k {
-                &ty::Ref(_, impl_ty, impl_mutbl) => {
-                    obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty)
-                }
-                _ => false,
-            },
-            ty::Adt(obl_def, obl_args) => match k {
-                &ty::Adt(impl_def, impl_args) => {
-                    obl_def == impl_def && self.args_may_unify(obl_args, impl_args)
-                }
-                _ => false,
-            },
-            ty::Pat(obl_ty, _) => {
-                // FIXME(pattern_types): take pattern into account
-                matches!(k, &ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty))
-            }
-            ty::Slice(obl_ty) => {
-                matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty))
-            }
-            ty::Array(obl_ty, obl_len) => match k {
-                &ty::Array(impl_ty, impl_len) => {
-                    self.types_may_unify(obl_ty, impl_ty)
-                        && self.consts_may_unify(obl_len, impl_len)
-                }
-                _ => false,
-            },
-            ty::Tuple(obl) => match k {
-                &ty::Tuple(imp) => {
-                    obl.len() == imp.len()
-                        && iter::zip(obl, imp).all(|(obl, imp)| self.types_may_unify(obl, imp))
-                }
-                _ => false,
-            },
-            ty::RawPtr(obl_ty, obl_mutbl) => match *k {
-                ty::RawPtr(imp_ty, imp_mutbl) => {
-                    obl_mutbl == imp_mutbl && self.types_may_unify(obl_ty, imp_ty)
-                }
-                _ => false,
-            },
-            ty::Dynamic(obl_preds, ..) => {
-                // Ideally we would walk the existential predicates here or at least
-                // compare their length. But considering that the relevant `Relate` impl
-                // actually sorts and deduplicates these, that doesn't work.
-                matches!(k, ty::Dynamic(impl_preds, ..) if
-                    obl_preds.principal_def_id() == impl_preds.principal_def_id()
-                )
-            }
-            ty::FnPtr(obl_sig) => match k {
-                ty::FnPtr(impl_sig) => {
-                    let ty::FnSig { inputs_and_output, c_variadic, safety, abi } =
-                        obl_sig.skip_binder();
-                    let impl_sig = impl_sig.skip_binder();
-
-                    abi == impl_sig.abi
-                        && c_variadic == impl_sig.c_variadic
-                        && safety == impl_sig.safety
-                        && inputs_and_output.len() == impl_sig.inputs_and_output.len()
-                        && iter::zip(inputs_and_output, impl_sig.inputs_and_output)
-                            .all(|(obl, imp)| self.types_may_unify(obl, imp))
-                }
-                _ => false,
-            },
-
-            // Impls cannot contain these types as these cannot be named directly.
-            ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => false,
-
-            // Placeholder types don't unify with anything on their own
-            ty::Placeholder(..) | ty::Bound(..) => false,
-
-            // Depending on the value of `treat_obligation_params`, we either
-            // treat generic parameters like placeholders or like inference variables.
-            ty::Param(_) => match self.treat_obligation_params {
-                TreatParams::ForLookup => false,
-                TreatParams::AsCandidateKey => true,
-            },
-
-            ty::Infer(ty::IntVar(_)) => impl_ty.is_integral(),
-
-            ty::Infer(ty::FloatVar(_)) => impl_ty.is_floating_point(),
-
-            ty::Infer(_) => true,
-
-            // As we're walking the whole type, it may encounter projections
-            // inside of binders and what not, so we're just going to assume that
-            // projections can unify with other stuff.
-            //
-            // Looking forward to lazy normalization this is the safer strategy anyways.
-            ty::Alias(..) => true,
-
-            ty::Error(_) => true,
-
-            ty::CoroutineWitness(..) => {
-                bug!("unexpected obligation type: {:?}", obligation_ty)
-            }
-        }
-    }
-
-    pub fn consts_may_unify(self, obligation_ct: ty::Const<'_>, impl_ct: ty::Const<'_>) -> bool {
-        let impl_val = match impl_ct.kind() {
-            ty::ConstKind::Expr(_)
-            | ty::ConstKind::Param(_)
-            | ty::ConstKind::Unevaluated(_)
-            | ty::ConstKind::Error(_) => {
-                return true;
-            }
-            ty::ConstKind::Value(_, impl_val) => impl_val,
-            ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
-                bug!("unexpected impl arg: {:?}", impl_ct)
-            }
-        };
-
-        match obligation_ct.kind() {
-            ty::ConstKind::Param(_) => match self.treat_obligation_params {
-                TreatParams::ForLookup => false,
-                TreatParams::AsCandidateKey => true,
-            },
-
-            // Placeholder consts don't unify with anything on their own
-            ty::ConstKind::Placeholder(_) => false,
-
-            // As we don't necessarily eagerly evaluate constants,
-            // they might unify with any value.
-            ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => {
-                true
-            }
-            ty::ConstKind::Value(_, obl_val) => obl_val == impl_val,
-
-            ty::ConstKind::Infer(_) => true,
-
-            ty::ConstKind::Bound(..) => {
-                bug!("unexpected obl const: {:?}", obligation_ct)
-            }
-        }
-    }
-}
+pub type SimplifiedType = rustc_type_ir::fast_reject::SimplifiedType<DefId>;
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 844023df1e3..11ed0bdaa70 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -394,7 +394,7 @@ impl<'tcx> GenericPredicates<'tcx> {
     }
 
     pub fn instantiate_own_identity(&self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
-        EarlyBinder::bind(self.predicates).instantiate_identity_iter_copied()
+        EarlyBinder::bind(self.predicates).iter_identity_copied()
     }
 
     #[instrument(level = "debug", skip(self, tcx))]
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index efcf428c213..9be7370a1c2 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -4,7 +4,6 @@
 use crate::middle::region;
 use crate::mir;
 use crate::ty;
-use crate::ty::fast_reject::SimplifiedType;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::HashingControls;
@@ -57,18 +56,6 @@ where
     }
 }
 
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for SimplifiedType {
-    type KeyType = Fingerprint;
-
-    #[inline]
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint {
-        let mut hasher = StableHasher::new();
-        let mut hcx: StableHashingContext<'a> = hcx.clone();
-        self.hash_stable(&mut hcx, &mut hasher);
-        hasher.finish()
-    }
-}
-
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::GenericArg<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         self.unpack().hash_stable(hcx, hasher);
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 1ba8820e0e1..c50a98e88fd 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -1,23 +1,26 @@
+use crate::error;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
-use crate::ty::{EarlyBinder, GenericArgs, GenericArgsRef, TypeVisitableExt};
+use crate::ty::print::{shrunk_instance_name, FmtPrinter, Printer};
+use crate::ty::{
+    self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::FiniteBitSet;
-use rustc_macros::{
-    Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable, TypeVisitable,
-};
+use rustc_macros::{Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable};
 use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
 use rustc_span::def_id::LOCAL_CRATE;
-use rustc_span::Symbol;
+use rustc_span::{Span, Symbol, DUMMY_SP};
 use tracing::{debug, instrument};
 
 use std::assert_matches::assert_matches;
 use std::fmt;
+use std::path::PathBuf;
 
 /// An `InstanceKind` along with the args that are needed to substitute the instance.
 ///
@@ -385,7 +388,40 @@ impl<'tcx> InstanceKind<'tcx> {
     }
 }
 
-fn fmt_instance(
+fn type_length<'tcx>(item: impl TypeVisitable<TyCtxt<'tcx>>) -> usize {
+    struct Visitor<'tcx> {
+        type_length: usize,
+        cache: FxHashMap<Ty<'tcx>, usize>,
+    }
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> {
+        fn visit_ty(&mut self, t: Ty<'tcx>) {
+            if let Some(&value) = self.cache.get(&t) {
+                self.type_length += value;
+                return;
+            }
+
+            let prev = self.type_length;
+            self.type_length += 1;
+            t.super_visit_with(self);
+
+            // We don't try to use the cache if the type is fairly small.
+            if self.type_length > 16 {
+                self.cache.insert(t, self.type_length - prev);
+            }
+        }
+
+        fn visit_const(&mut self, ct: ty::Const<'tcx>) {
+            self.type_length += 1;
+            ct.super_visit_with(self);
+        }
+    }
+    let mut visitor = Visitor { type_length: 0, cache: Default::default() };
+    item.visit_with(&mut visitor);
+
+    visitor.type_length
+}
+
+pub fn fmt_instance(
     f: &mut fmt::Formatter<'_>,
     instance: Instance<'_>,
     type_length: Option<rustc_session::Limit>,
@@ -485,19 +521,30 @@ impl<'tcx> Instance<'tcx> {
     ///
     /// Presuming that coherence and type-check have succeeded, if this method is invoked
     /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
-    /// `Ok(Some(instance))`.
+    /// `Ok(Some(instance))`, **except** for when the instance's inputs hit the type size limit,
+    /// in which case it may bail out and return `Ok(None)`.
     ///
     /// Returns `Err(ErrorGuaranteed)` when the `Instance` resolution process
     /// couldn't complete due to errors elsewhere - this is distinct
     /// from `Ok(None)` to avoid misleading diagnostics when an error
     /// has already been/will be emitted, for the original cause
     #[instrument(level = "debug", skip(tcx), ret)]
-    pub fn resolve(
+    pub fn try_resolve(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
     ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
+        // Rust code can easily create exponentially-long types using only a
+        // polynomial recursion depth. Even with the default recursion
+        // depth, you can easily get cases that take >2^60 steps to run,
+        // which means that rustc basically hangs.
+        //
+        // Bail out in these cases to avoid that bad user experience.
+        if !tcx.type_length_limit().value_within_limit(type_length(args)) {
+            return Ok(None);
+        }
+
         // All regions in the result of this query are erased, so it's
         // fine to erase all of the input regions.
 
@@ -505,7 +552,7 @@ impl<'tcx> Instance<'tcx> {
         // below is more likely to ignore the bounds in scope (e.g. if the only
         // generic parameters mentioned by `args` were lifetime ones).
         let args = tcx.erase_regions(args);
-        tcx.resolve_instance(tcx.erase_regions(param_env.and((def_id, args))))
+        tcx.resolve_instance_raw(tcx.erase_regions(param_env.and((def_id, args))))
     }
 
     pub fn expect_resolve(
@@ -513,10 +560,48 @@ impl<'tcx> Instance<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
+        span: Span,
     ) -> Instance<'tcx> {
-        match ty::Instance::resolve(tcx, param_env, def_id, args) {
+        // We compute the span lazily, to avoid unnecessary query calls.
+        // If `span` is a DUMMY_SP, and the def id is local, then use the
+        // def span of the def id.
+        let span_or_local_def_span =
+            || if span.is_dummy() && def_id.is_local() { tcx.def_span(def_id) } else { span };
+
+        match ty::Instance::try_resolve(tcx, param_env, def_id, args) {
             Ok(Some(instance)) => instance,
-            instance => bug!(
+            Ok(None) => {
+                let type_length = type_length(args);
+                if !tcx.type_length_limit().value_within_limit(type_length) {
+                    let (shrunk, written_to_path) =
+                        shrunk_instance_name(tcx, Instance::new(def_id, args));
+                    let mut path = PathBuf::new();
+                    let was_written = if let Some(path2) = written_to_path {
+                        path = path2;
+                        Some(())
+                    } else {
+                        None
+                    };
+                    tcx.dcx().emit_fatal(error::TypeLengthLimit {
+                        // We don't use `def_span(def_id)` so that diagnostics point
+                        // to the crate root during mono instead of to foreign items.
+                        // This is arguably better.
+                        span: span_or_local_def_span(),
+                        shrunk,
+                        was_written,
+                        path,
+                        type_length,
+                    });
+                } else {
+                    span_bug!(
+                        span_or_local_def_span(),
+                        "failed to resolve instance for {}",
+                        tcx.def_path_str_with_args(def_id, args)
+                    )
+                }
+            }
+            instance => span_bug!(
+                span_or_local_def_span(),
                 "failed to resolve instance for {}: {instance:#?}",
                 tcx.def_path_str_with_args(def_id, args)
             ),
@@ -533,7 +618,7 @@ impl<'tcx> Instance<'tcx> {
         // Use either `resolve_closure` or `resolve_for_vtable`
         assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}");
         let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr);
-        Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
+        Instance::try_resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
             match resolved.def {
                 InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => {
                     debug!(" => fn pointer created for function with #[track_caller]");
@@ -571,77 +656,82 @@ impl<'tcx> Instance<'tcx> {
         })
     }
 
-    pub fn resolve_for_vtable(
+    pub fn expect_resolve_for_vtable(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
-    ) -> Option<Instance<'tcx>> {
+        span: Span,
+    ) -> Instance<'tcx> {
         debug!("resolve_for_vtable(def_id={:?}, args={:?})", def_id, args);
         let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
         let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty()
             && fn_sig.input(0).skip_binder().is_param(0)
             && tcx.generics_of(def_id).has_self;
+
         if is_vtable_shim {
             debug!(" => associated item with unsizeable self: Self");
-            Some(Instance { def: InstanceKind::VTableShim(def_id), args })
-        } else {
-            let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable);
-            Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
-                match resolved.def {
-                    InstanceKind::Item(def) => {
-                        // We need to generate a shim when we cannot guarantee that
-                        // the caller of a trait object method will be aware of
-                        // `#[track_caller]` - this ensures that the caller
-                        // and callee ABI will always match.
-                        //
-                        // The shim is generated when all of these conditions are met:
-                        //
-                        // 1) The underlying method expects a caller location parameter
-                        // in the ABI
-                        if resolved.def.requires_caller_location(tcx)
-                            // 2) The caller location parameter comes from having `#[track_caller]`
-                            // on the implementation, and *not* on the trait method.
-                            && !tcx.should_inherit_track_caller(def)
-                            // If the method implementation comes from the trait definition itself
-                            // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
-                            // then we don't need to generate a shim. This check is needed because
-                            // `should_inherit_track_caller` returns `false` if our method
-                            // implementation comes from the trait block, and not an impl block
-                            && !matches!(
-                                tcx.opt_associated_item(def),
-                                Some(ty::AssocItem {
-                                    container: ty::AssocItemContainer::TraitContainer,
-                                    ..
-                                })
-                            )
-                        {
-                            if tcx.is_closure_like(def) {
-                                debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
-                                       def, def_id, args);
-
-                                // Create a shim for the `FnOnce/FnMut/Fn` method we are calling
-                                // - unlike functions, invoking a closure always goes through a
-                                // trait.
-                                resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args };
-                            } else {
-                                debug!(
-                                    " => vtable fn pointer created for function with #[track_caller]: {:?}", def
-                                );
-                                resolved.def = InstanceKind::ReifyShim(def, reason);
-                            }
-                        }
-                    }
-                    InstanceKind::Virtual(def_id, _) => {
-                        debug!(" => vtable fn pointer created for virtual call");
-                        resolved.def = InstanceKind::ReifyShim(def_id, reason)
+            return Instance { def: InstanceKind::VTableShim(def_id), args };
+        }
+
+        let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, span);
+
+        let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable);
+        match resolved.def {
+            InstanceKind::Item(def) => {
+                // We need to generate a shim when we cannot guarantee that
+                // the caller of a trait object method will be aware of
+                // `#[track_caller]` - this ensures that the caller
+                // and callee ABI will always match.
+                //
+                // The shim is generated when all of these conditions are met:
+                //
+                // 1) The underlying method expects a caller location parameter
+                // in the ABI
+                if resolved.def.requires_caller_location(tcx)
+                        // 2) The caller location parameter comes from having `#[track_caller]`
+                        // on the implementation, and *not* on the trait method.
+                        && !tcx.should_inherit_track_caller(def)
+                        // If the method implementation comes from the trait definition itself
+                        // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
+                        // then we don't need to generate a shim. This check is needed because
+                        // `should_inherit_track_caller` returns `false` if our method
+                        // implementation comes from the trait block, and not an impl block
+                        && !matches!(
+                            tcx.opt_associated_item(def),
+                            Some(ty::AssocItem {
+                                container: ty::AssocItemContainer::TraitContainer,
+                                ..
+                            })
+                        )
+                {
+                    if tcx.is_closure_like(def) {
+                        debug!(
+                            " => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
+                            def, def_id, args
+                        );
+
+                        // Create a shim for the `FnOnce/FnMut/Fn` method we are calling
+                        // - unlike functions, invoking a closure always goes through a
+                        // trait.
+                        resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args };
+                    } else {
+                        debug!(
+                            " => vtable fn pointer created for function with #[track_caller]: {:?}",
+                            def
+                        );
+                        resolved.def = InstanceKind::ReifyShim(def, reason);
                     }
-                    _ => {}
                 }
-
-                resolved
-            })
+            }
+            InstanceKind::Virtual(def_id, _) => {
+                debug!(" => vtable fn pointer created for virtual call");
+                resolved.def = InstanceKind::ReifyShim(def_id, reason)
+            }
+            _ => {}
         }
+
+        resolved
     }
 
     pub fn resolve_closure(
@@ -661,13 +751,25 @@ impl<'tcx> Instance<'tcx> {
     pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
         let def_id = tcx.require_lang_item(LangItem::DropInPlace, None);
         let args = tcx.mk_args(&[ty.into()]);
-        Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
+        Instance::expect_resolve(
+            tcx,
+            ty::ParamEnv::reveal_all(),
+            def_id,
+            args,
+            ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP),
+        )
     }
 
     pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
         let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None);
         let args = tcx.mk_args(&[ty.into()]);
-        Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
+        Instance::expect_resolve(
+            tcx,
+            ty::ParamEnv::reveal_all(),
+            def_id,
+            args,
+            ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP),
+        )
     }
 
     #[instrument(level = "debug", skip(tcx), ret)]
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 7d57d88f40f..e1bd3ad8ad3 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -148,6 +148,7 @@ mod closure;
 mod consts;
 mod context;
 mod diagnostics;
+mod elaborate_impl;
 mod erase_regions;
 mod generic_args;
 mod generics;
@@ -1967,8 +1968,13 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     #[inline]
+    pub fn is_const_trait(self, def_id: DefId) -> bool {
+        self.trait_def(def_id).constness == hir::Constness::Const
+    }
+
+    #[inline]
     pub fn is_const_default_method(self, def_id: DefId) -> bool {
-        matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
+        matches!(self.trait_of_item(def_id), Some(trait_id) if self.is_const_trait(trait_id))
     }
 
     pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool {
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index e9b37503bb3..5d6352c57ce 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -46,6 +46,10 @@ pub struct Predicate<'tcx>(
 );
 
 impl<'tcx> rustc_type_ir::inherent::Predicate<TyCtxt<'tcx>> for Predicate<'tcx> {
+    fn as_clause(self) -> Option<ty::Clause<'tcx>> {
+        self.as_clause()
+    }
+
     fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool {
         self.is_coinductive(interner)
     }
@@ -173,7 +177,11 @@ pub struct Clause<'tcx>(
     pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
 );
 
-impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {}
+impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {
+    fn instantiate_supertrait(self, tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> Self {
+        self.instantiate_supertrait(tcx, trait_ref)
+    }
+}
 
 impl<'tcx> rustc_type_ir::inherent::IntoKind for Clause<'tcx> {
     type Kind = ty::Binder<'tcx, ClauseKind<'tcx>>;
@@ -341,6 +349,14 @@ impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> {
             _ => None,
         })
     }
+
+    pub fn without_auto_traits(
+        &self,
+    ) -> impl Iterator<Item = ty::PolyExistentialPredicate<'tcx>> + '_ {
+        self.iter().filter(|predicate| {
+            !matches!(predicate.as_ref().skip_binder(), ExistentialPredicate::AutoTrait(_))
+        })
+    }
 }
 
 pub type PolyTraitRef<'tcx> = ty::Binder<'tcx, TraitRef<'tcx>>;
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 3c27df9529a..c165790548d 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -1,5 +1,7 @@
+use std::path::PathBuf;
+
 use crate::ty::GenericArg;
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{self, ShortInstance, Ty, TyCtxt};
 
 use hir::def::Namespace;
 use rustc_data_structures::fx::FxHashSet;
@@ -356,3 +358,31 @@ where
         with_no_trimmed_paths!(Self::print(t, fmt))
     }
 }
+
+/// Format instance name that is already known to be too long for rustc.
+/// Show only the first 2 types if it is longer than 32 characters to avoid blasting
+/// the user's terminal with thousands of lines of type-name.
+///
+/// If the type name is longer than before+after, it will be written to a file.
+pub fn shrunk_instance_name<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: ty::Instance<'tcx>,
+) -> (String, Option<PathBuf>) {
+    let s = instance.to_string();
+
+    // Only use the shrunk version if it's really shorter.
+    // This also avoids the case where before and after slices overlap.
+    if s.chars().nth(33).is_some() {
+        let shrunk = format!("{}", ShortInstance(instance, 4));
+        if shrunk == s {
+            return (s, None);
+        }
+
+        let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None);
+        let written_to_path = std::fs::write(&path, s).ok().map(|_| path);
+
+        (shrunk, written_to_path)
+    } else {
+        (s, None)
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 19700353f59..df080b2887b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,7 +1,6 @@
 use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::query::IntoQueryParam;
 use crate::query::Providers;
-use crate::traits::util::{super_predicates_for_pretty_printing, supertraits_for_pretty_printing};
 use crate::ty::GenericArgKind;
 use crate::ty::{
     ConstInt, Expr, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable,
@@ -23,6 +22,7 @@ use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::FileNameDisplayPreference;
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
+use rustc_type_ir::{elaborate, Upcast as _};
 use smallvec::SmallVec;
 
 use std::cell::Cell;
@@ -1255,14 +1255,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 entry.has_fn_once = true;
                 return;
             } else if self.tcx().is_lang_item(trait_def_id, LangItem::FnMut) {
-                let super_trait_ref = supertraits_for_pretty_printing(self.tcx(), trait_ref)
+                let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref)
                     .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
                     .unwrap();
 
                 fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref);
                 return;
             } else if self.tcx().is_lang_item(trait_def_id, LangItem::Fn) {
-                let super_trait_ref = supertraits_for_pretty_printing(self.tcx(), trait_ref)
+                let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref)
                     .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
                     .unwrap();
 
@@ -1343,10 +1343,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     let bound_principal_with_self = bound_principal
                         .with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self);
 
-                    let super_projections: Vec<_> =
-                        super_predicates_for_pretty_printing(cx.tcx(), bound_principal_with_self)
-                            .filter_map(|clause| clause.as_projection_clause())
-                            .collect();
+                    let clause: ty::Clause<'tcx> = bound_principal_with_self.upcast(cx.tcx());
+                    let super_projections: Vec<_> = elaborate::elaborate(cx.tcx(), [clause])
+                        .filter_only_self()
+                        .filter_map(|clause| clause.as_projection_clause())
+                        .collect();
 
                     let mut projections: Vec<_> = predicates
                         .projection_bounds()
@@ -1667,7 +1668,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                                 Some(GlobalAlloc::Static(def_id)) => {
                                     p!(write("<static({:?})>", def_id))
                                 }
-                                Some(GlobalAlloc::Function(_)) => p!("<function>"),
+                                Some(GlobalAlloc::Function { .. }) => p!("<function>"),
                                 Some(GlobalAlloc::VTable(..)) => p!("<vtable>"),
                                 None => p!("<dangling pointer>"),
                             }
@@ -1679,7 +1680,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             ty::FnPtr(_) => {
                 // FIXME: We should probably have a helper method to share code with the "Byte strings"
                 // printing above (which also has to handle pointers to all sorts of things).
-                if let Some(GlobalAlloc::Function(instance)) =
+                if let Some(GlobalAlloc::Function { instance, .. }) =
                     self.tcx().try_get_global_alloc(prov.alloc_id())
                 {
                     self.typed_value(
@@ -1710,22 +1711,24 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             ty::Bool if int == ScalarInt::FALSE => p!("false"),
             ty::Bool if int == ScalarInt::TRUE => p!("true"),
             // Float
-            ty::Float(ty::FloatTy::F16) => {
-                let val = Half::try_from(int).unwrap();
-                p!(write("{}{}f16", val, if val.is_finite() { "" } else { "_" }))
-            }
-            ty::Float(ty::FloatTy::F32) => {
-                let val = Single::try_from(int).unwrap();
-                p!(write("{}{}f32", val, if val.is_finite() { "" } else { "_" }))
-            }
-            ty::Float(ty::FloatTy::F64) => {
-                let val = Double::try_from(int).unwrap();
-                p!(write("{}{}f64", val, if val.is_finite() { "" } else { "_" }))
-            }
-            ty::Float(ty::FloatTy::F128) => {
-                let val = Quad::try_from(int).unwrap();
-                p!(write("{}{}f128", val, if val.is_finite() { "" } else { "_" }))
-            }
+            ty::Float(fty) => match fty {
+                ty::FloatTy::F16 => {
+                    let val = Half::try_from(int).unwrap();
+                    p!(write("{}{}f16", val, if val.is_finite() { "" } else { "_" }))
+                }
+                ty::FloatTy::F32 => {
+                    let val = Single::try_from(int).unwrap();
+                    p!(write("{}{}f32", val, if val.is_finite() { "" } else { "_" }))
+                }
+                ty::FloatTy::F64 => {
+                    let val = Double::try_from(int).unwrap();
+                    p!(write("{}{}f64", val, if val.is_finite() { "" } else { "_" }))
+                }
+                ty::FloatTy::F128 => {
+                    let val = Quad::try_from(int).unwrap();
+                    p!(write("{}{}f128", val, if val.is_finite() { "" } else { "_" }))
+                }
+            },
             // Int
             ty::Uint(_) | ty::Int(_) => {
                 let int =
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index b169d672a84..ebf0d7ed737 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -10,18 +10,6 @@ use crate::ty::{self as ty, Ty, TyCtxt};
 
 pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>;
 
-/// Whether aliases should be related structurally or not. Used
-/// to adjust the behavior of generalization and combine.
-///
-/// This should always be `No` unless in a few special-cases when
-/// instantiating canonical responses and in the new solver. Each
-/// such case should have a comment explaining why it is used.
-#[derive(Debug, Copy, Clone)]
-pub enum StructurallyRelateAliases {
-    Yes,
-    No,
-}
-
 impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> {
     #[inline]
     fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index ff40a726fbc..d2b444a066b 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -68,6 +68,10 @@ impl<'tcx> ty::CoroutineArgs<TyCtxt<'tcx>> {
     const RETURNED: usize = 1;
     /// Coroutine has been poisoned.
     const POISONED: usize = 2;
+    /// Number of variants to reserve in coroutine state. Corresponds to
+    /// `UNRESUMED` (beginning of a coroutine) and `RETURNED`/`POISONED`
+    /// (end of a coroutine) states.
+    const RESERVED_VARIANTS: usize = 3;
 
     const UNRESUMED_NAME: &'static str = "Unresumed";
     const RETURNED_NAME: &'static str = "Returned";
@@ -116,7 +120,7 @@ impl<'tcx> ty::CoroutineArgs<TyCtxt<'tcx>> {
             Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME),
             Self::RETURNED => Cow::from(Self::RETURNED_NAME),
             Self::POISONED => Cow::from(Self::POISONED_NAME),
-            _ => Cow::from(format!("Suspend{}", v.as_usize() - 3)),
+            _ => Cow::from(format!("Suspend{}", v.as_usize() - Self::RESERVED_VARIANTS)),
         }
     }
 
@@ -807,6 +811,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
         Ty::new_var(tcx, vid)
     }
 
+    fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamTy) -> Self {
+        Ty::new_param(tcx, param.index, param.name)
+    }
+
+    fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType) -> Self {
+        Ty::new_placeholder(tcx, placeholder)
+    }
+
     fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundTy) -> Self {
         Ty::new_bound(interner, debruijn, var)
     }
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 4dba97c3b5b..da5860043c9 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -18,6 +18,9 @@ pub struct TraitDef {
 
     pub safety: hir::Safety,
 
+    /// Whether this trait has been annotated with `#[const_trait]`.
+    pub constness: hir::Constness,
+
     /// If `true`, then this trait had the `#[rustc_paren_sugar]`
     /// attribute, indicating that it should be used with `Foo()`
     /// sugar. This is a temporary thing -- eventually any trait will
@@ -31,7 +34,7 @@ pub struct TraitDef {
     /// and thus `impl`s of it are allowed to overlap.
     pub is_marker: bool,
 
-    /// If `true`, then this trait has to `#[rustc_coinductive]` attribute or
+    /// If `true`, then this trait has the `#[rustc_coinductive]` attribute or
     /// is an auto trait. This indicates that trait solver cycles involving an
     /// `X: ThisTrait` goal are accepted.
     ///
@@ -40,6 +43,11 @@ pub struct TraitDef {
     /// also have already switched to the new trait solver.
     pub is_coinductive: bool,
 
+    /// If `true`, then this trait has the `#[fundamental]` attribute. This
+    /// affects how conherence computes whether a trait may have trait implementations
+    /// added in the future.
+    pub is_fundamental: bool,
+
     /// If `true`, then this trait has the `#[rustc_skip_during_method_dispatch(array)]`
     /// attribute, indicating that editions before 2021 should not consider this trait
     /// during method dispatch if the receiver is an array.
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index e0f204a687f..efcaf89081f 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -78,23 +78,6 @@ impl<'tcx> GenericArg<'tcx> {
     pub fn walk(self) -> TypeWalker<'tcx> {
         TypeWalker::new(self)
     }
-
-    /// Iterator that walks the immediate children of `self`. Hence
-    /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
-    /// (but not `i32`, like `walk`).
-    ///
-    /// Iterator only walks items once.
-    /// It accepts visited set, updates it with all visited types
-    /// and skips any types that are already there.
-    pub fn walk_shallow(
-        self,
-        visited: &mut SsoHashSet<GenericArg<'tcx>>,
-    ) -> impl Iterator<Item = GenericArg<'tcx>> {
-        let mut stack = SmallVec::new();
-        push_inner(&mut stack, self);
-        stack.retain(|a| visited.insert(*a));
-        stack.into_iter()
-    }
 }
 
 impl<'tcx> Ty<'tcx> {
diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs
index dc1d73684f4..0815c291173 100644
--- a/compiler/rustc_middle/src/util/call_kind.rs
+++ b/compiler/rustc_middle/src/util/call_kind.rs
@@ -98,7 +98,7 @@ pub fn call_kind<'tcx>(
         Some(CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) })
     } else if is_deref {
         let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
-            Instance::resolve(tcx, param_env, deref_target, method_args).transpose()
+            Instance::try_resolve(tcx, param_env, deref_target, method_args).transpose()
         });
         if let Some(Ok(instance)) = deref_target {
             let deref_target_ty = instance.ty(tcx, param_env);
diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs
index 876faca5172..204ee45bfa2 100644
--- a/compiler/rustc_mir_build/src/build/coverageinfo.rs
+++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs
@@ -2,7 +2,7 @@ use std::assert_matches::assert_matches;
 use std::collections::hash_map::Entry;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
+use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind};
 use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp};
 use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir};
 use rustc_middle::ty::TyCtxt;
@@ -13,16 +13,25 @@ use crate::build::{Builder, CFG};
 
 mod mcdc;
 
-pub(crate) struct BranchInfoBuilder {
+/// Collects coverage-related information during MIR building, to eventually be
+/// turned into a function's [`CoverageInfoHi`] when MIR building is complete.
+pub(crate) struct CoverageInfoBuilder {
     /// Maps condition expressions to their enclosing `!`, for better instrumentation.
     nots: FxHashMap<ExprId, NotInfo>,
 
     markers: BlockMarkerGen,
-    branch_spans: Vec<BranchSpan>,
 
+    /// Present if branch coverage is enabled.
+    branch_info: Option<BranchInfo>,
+    /// Present if MC/DC coverage is enabled.
     mcdc_info: Option<MCDCInfoBuilder>,
 }
 
+#[derive(Default)]
+struct BranchInfo {
+    branch_spans: Vec<BranchSpan>,
+}
+
 #[derive(Clone, Copy)]
 struct NotInfo {
     /// When visiting the associated expression as a branch condition, treat this
@@ -62,20 +71,20 @@ impl BlockMarkerGen {
     }
 }
 
-impl BranchInfoBuilder {
-    /// Creates a new branch info builder, but only if branch coverage instrumentation
+impl CoverageInfoBuilder {
+    /// Creates a new coverage info builder, but only if coverage instrumentation
     /// is enabled and `def_id` represents a function that is eligible for coverage.
     pub(crate) fn new_if_enabled(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Self> {
-        if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) {
-            Some(Self {
-                nots: FxHashMap::default(),
-                markers: BlockMarkerGen::default(),
-                branch_spans: vec![],
-                mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new),
-            })
-        } else {
-            None
+        if !tcx.sess.instrument_coverage() || !tcx.is_eligible_for_coverage(def_id) {
+            return None;
         }
+
+        Some(Self {
+            nots: FxHashMap::default(),
+            markers: BlockMarkerGen::default(),
+            branch_info: tcx.sess.instrument_coverage_branch().then(BranchInfo::default),
+            mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new),
+        })
     }
 
     /// Unary `!` expressions inside an `if` condition are lowered by lowering
@@ -88,6 +97,12 @@ impl BranchInfoBuilder {
     pub(crate) fn visit_unary_not(&mut self, thir: &Thir<'_>, unary_not: ExprId) {
         assert_matches!(thir[unary_not].kind, ExprKind::Unary { op: UnOp::Not, .. });
 
+        // The information collected by this visitor is only needed when branch
+        // coverage or higher is enabled.
+        if self.branch_info.is_none() {
+            return;
+        }
+
         self.visit_with_not_info(
             thir,
             unary_not,
@@ -137,40 +152,40 @@ impl BranchInfoBuilder {
                 false_block,
                 inject_block_marker,
             );
-        } else {
-            let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
-            let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);
-
-            self.branch_spans.push(BranchSpan {
-                span: source_info.span,
-                true_marker,
-                false_marker,
-            });
+            return;
         }
+
+        // Bail out if branch coverage is not enabled.
+        let Some(branch_info) = self.branch_info.as_mut() else { return };
+
+        let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
+        let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);
+
+        branch_info.branch_spans.push(BranchSpan {
+            span: source_info.span,
+            true_marker,
+            false_marker,
+        });
     }
 
-    pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> {
-        let Self {
-            nots: _,
-            markers: BlockMarkerGen { num_block_markers },
-            branch_spans,
-            mcdc_info,
-        } = self;
+    pub(crate) fn into_done(self) -> Box<CoverageInfoHi> {
+        let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info, mcdc_info } =
+            self;
 
-        if num_block_markers == 0 {
-            assert!(branch_spans.is_empty());
-            return None;
-        }
+        let branch_spans =
+            branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default();
 
         let (mcdc_decision_spans, mcdc_branch_spans) =
             mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default();
 
-        Some(Box::new(mir::coverage::BranchInfo {
+        // For simplicity, always return an info struct (without Option), even
+        // if there's nothing interesting in it.
+        Box::new(CoverageInfoHi {
             num_block_markers,
             branch_spans,
             mcdc_branch_spans,
             mcdc_decision_spans,
-        }))
+        })
     }
 }
 
@@ -184,7 +199,7 @@ impl<'tcx> Builder<'_, 'tcx> {
         block: &mut BasicBlock,
     ) {
         // Bail out if condition coverage is not enabled for this function.
-        let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
+        let Some(coverage_info) = self.coverage_info.as_mut() else { return };
         if !self.tcx.sess.instrument_coverage_condition() {
             return;
         };
@@ -224,7 +239,7 @@ impl<'tcx> Builder<'_, 'tcx> {
         );
 
         // Separate path for handling branches when MC/DC is enabled.
-        branch_info.register_two_way_branch(
+        coverage_info.register_two_way_branch(
             self.tcx,
             &mut self.cfg,
             source_info,
@@ -247,12 +262,12 @@ impl<'tcx> Builder<'_, 'tcx> {
         mut then_block: BasicBlock,
         mut else_block: BasicBlock,
     ) {
-        // Bail out if branch coverage is not enabled for this function.
-        let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
+        // Bail out if coverage is not enabled for this function.
+        let Some(coverage_info) = self.coverage_info.as_mut() else { return };
 
         // If this condition expression is nested within one or more `!` expressions,
         // replace it with the enclosing `!` collected by `visit_unary_not`.
-        if let Some(&NotInfo { enclosing_not, is_flipped }) = branch_info.nots.get(&expr_id) {
+        if let Some(&NotInfo { enclosing_not, is_flipped }) = coverage_info.nots.get(&expr_id) {
             expr_id = enclosing_not;
             if is_flipped {
                 std::mem::swap(&mut then_block, &mut else_block);
@@ -261,7 +276,7 @@ impl<'tcx> Builder<'_, 'tcx> {
 
         let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };
 
-        branch_info.register_two_way_branch(
+        coverage_info.register_two_way_branch(
             self.tcx,
             &mut self.cfg,
             source_info,
@@ -280,13 +295,11 @@ impl<'tcx> Builder<'_, 'tcx> {
         true_block: BasicBlock,
         false_block: BasicBlock,
     ) {
-        // Bail out if branch coverage is not enabled for this function.
-        let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
-
-        // FIXME(#124144) This may need special handling when MC/DC is enabled.
+        // Bail out if coverage is not enabled for this function.
+        let Some(coverage_info) = self.coverage_info.as_mut() else { return };
 
         let source_info = SourceInfo { span: pattern.span, scope: self.source_scope };
-        branch_info.register_two_way_branch(
+        coverage_info.register_two_way_branch(
             self.tcx,
             &mut self.cfg,
             source_info,
diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs
index f97e9ef60a2..3aa6e708476 100644
--- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs
+++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs
@@ -250,24 +250,24 @@ impl MCDCInfoBuilder {
 
 impl Builder<'_, '_> {
     pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) {
-        if let Some(branch_info) = self.coverage_branch_info.as_mut()
-            && let Some(mcdc_info) = branch_info.mcdc_info.as_mut()
+        if let Some(coverage_info) = self.coverage_info.as_mut()
+            && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut()
         {
             mcdc_info.state.record_conditions(logical_op, span);
         }
     }
 
     pub(crate) fn mcdc_increment_depth_if_enabled(&mut self) {
-        if let Some(branch_info) = self.coverage_branch_info.as_mut()
-            && let Some(mcdc_info) = branch_info.mcdc_info.as_mut()
+        if let Some(coverage_info) = self.coverage_info.as_mut()
+            && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut()
         {
             mcdc_info.state.decision_ctx_stack.push(MCDCDecisionCtx::default());
         };
     }
 
     pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) {
-        if let Some(branch_info) = self.coverage_branch_info.as_mut()
-            && let Some(mcdc_info) = branch_info.mcdc_info.as_mut()
+        if let Some(coverage_info) = self.coverage_info.as_mut()
+            && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut()
         {
             if mcdc_info.state.decision_ctx_stack.pop().is_none() {
                 bug!("Unexpected empty decision stack");
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index a0a512a2eff..f6ebcbcbdc9 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -62,7 +62,7 @@ pub(super) fn build_custom_mir<'tcx>(
         tainted_by_errors: None,
         injection_phase: None,
         pass_count: 0,
-        coverage_branch_info: None,
+        coverage_info_hi: None,
         function_coverage_info: None,
     };
 
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 4b62afa61bb..91a3b53cc79 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -130,7 +130,7 @@ fn convert_to_hir_projections_and_truncate_for_capture(
 /// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of
 ///        `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`.
 ///        Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`.
-///     2. Since we only look at the projections here function will return `bar.x` as an a valid
+///     2. Since we only look at the projections here function will return `bar.x` as a valid
 ///        ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
 ///        list are being applied to the same root variable.
 fn is_ancestor_or_same_capture(
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 2bdeb579a02..88b76c46c90 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -2,7 +2,9 @@ use crate::build::scope::BreakableTarget;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
+use rustc_middle::span_bug;
 use rustc_middle::thir::*;
+use rustc_span::source_map::Spanned;
 use tracing::debug;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -91,9 +93,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             ExprKind::Return { value } => {
                 this.break_scope(block, value, BreakableTarget::Return, source_info)
             }
-            // FIXME(explicit_tail_calls): properly lower tail calls here
             ExprKind::Become { value } => {
-                this.break_scope(block, Some(value), BreakableTarget::Return, source_info)
+                let v = &this.thir[value];
+                let ExprKind::Scope { value, lint_level, region_scope } = v.kind else {
+                    span_bug!(v.span, "`thir_check_tail_calls` should have disallowed this {v:?}")
+                };
+
+                let v = &this.thir[value];
+                let ExprKind::Call { ref args, fun, fn_span, .. } = v.kind else {
+                    span_bug!(v.span, "`thir_check_tail_calls` should have disallowed this {v:?}")
+                };
+
+                this.in_scope((region_scope, source_info), lint_level, |this| {
+                    let fun = unpack!(block = this.as_local_operand(block, fun));
+                    let args: Box<[_]> = args
+                        .into_iter()
+                        .copied()
+                        .map(|arg| Spanned {
+                            node: unpack!(block = this.as_local_call_operand(block, arg)),
+                            span: this.thir.exprs[arg].span,
+                        })
+                        .collect();
+
+                    this.record_operands_moved(&args);
+
+                    debug!("expr_into_dest: fn_span={:?}", fn_span);
+
+                    unpack!(block = this.break_for_tail_call(block, &args, source_info));
+
+                    this.cfg.terminate(
+                        block,
+                        source_info,
+                        TerminatorKind::TailCall { func: fun, args, fn_span },
+                    );
+
+                    this.cfg.start_new_block().unit()
+                })
             }
             _ => {
                 assert!(
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index efed52231e3..5695c881ecc 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -160,8 +160,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // Improve branch coverage instrumentation by noting conditions
                 // nested within one or more `!` expressions.
                 // (Skipped if branch coverage is not enabled.)
-                if let Some(branch_info) = this.coverage_branch_info.as_mut() {
-                    branch_info.visit_unary_not(this.thir, expr_id);
+                if let Some(coverage_info) = this.coverage_info.as_mut() {
+                    coverage_info.visit_unary_not(this.thir, expr_id);
                 }
 
                 let local_scope = this.local_scope();
@@ -1468,6 +1468,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     break;
                 }
             }
+            if expand_until != 0 {
+                expand_until = i + 1;
+            }
         }
         let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);
 
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 601e5d4d3dc..0f9746cb719 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -218,8 +218,8 @@ struct Builder<'a, 'tcx> {
     lint_level_roots_cache: GrowableBitSet<hir::ItemLocalId>,
 
     /// Collects additional coverage information during MIR building.
-    /// Only present if branch coverage is enabled and this function is eligible.
-    coverage_branch_info: Option<coverageinfo::BranchInfoBuilder>,
+    /// Only present if coverage is enabled and this function is eligible.
+    coverage_info: Option<coverageinfo::CoverageInfoBuilder>,
 }
 
 type CaptureMap<'tcx> = SortedIndexMultiMap<usize, HirId, Capture<'tcx>>;
@@ -773,7 +773,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             unit_temp: None,
             var_debug_info: vec![],
             lint_level_roots_cache: GrowableBitSet::new_empty(),
-            coverage_branch_info: coverageinfo::BranchInfoBuilder::new_if_enabled(tcx, def),
+            coverage_info: coverageinfo::CoverageInfoBuilder::new_if_enabled(tcx, def),
         };
 
         assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
@@ -802,7 +802,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             self.coroutine,
             None,
         );
-        body.coverage_branch_info = self.coverage_branch_info.and_then(|b| b.into_done());
+        body.coverage_info_hi = self.coverage_info.map(|b| b.into_done());
         body
     }
 
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 5b6de39bb2e..948301e2ece 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -745,6 +745,91 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.cfg.terminate(block, source_info, TerminatorKind::UnwindResume);
     }
 
+    /// Sets up the drops for explict tail calls.
+    ///
+    /// Unlike other kinds of early exits, tail calls do not go through the drop tree.
+    /// Instead, all scheduled drops are immediately added to the CFG.
+    pub(crate) fn break_for_tail_call(
+        &mut self,
+        mut block: BasicBlock,
+        args: &[Spanned<Operand<'tcx>>],
+        source_info: SourceInfo,
+    ) -> BlockAnd<()> {
+        let arg_drops: Vec<_> = args
+            .iter()
+            .rev()
+            .filter_map(|arg| match &arg.node {
+                Operand::Copy(_) => bug!("copy op in tail call args"),
+                Operand::Move(place) => {
+                    let local =
+                        place.as_local().unwrap_or_else(|| bug!("projection in tail call args"));
+
+                    Some(DropData { source_info, local, kind: DropKind::Value })
+                }
+                Operand::Constant(_) => None,
+            })
+            .collect();
+
+        let mut unwind_to = self.diverge_cleanup_target(
+            self.scopes.scopes.iter().rev().nth(1).unwrap().region_scope,
+            DUMMY_SP,
+        );
+        let unwind_drops = &mut self.scopes.unwind_drops;
+
+        // the innermost scope contains only the destructors for the tail call arguments
+        // we only want to drop these in case of a panic, so we skip it
+        for scope in self.scopes.scopes[1..].iter().rev().skip(1) {
+            // FIXME(explicit_tail_calls) code duplication with `build_scope_drops`
+            for drop_data in scope.drops.iter().rev() {
+                let source_info = drop_data.source_info;
+                let local = drop_data.local;
+
+                match drop_data.kind {
+                    DropKind::Value => {
+                        // `unwind_to` should drop the value that we're about to
+                        // schedule. If dropping this value panics, then we continue
+                        // with the *next* value on the unwind path.
+                        debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
+                        debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
+                        unwind_to = unwind_drops.drops[unwind_to].next;
+
+                        let mut unwind_entry_point = unwind_to;
+
+                        // the tail call arguments must be dropped if any of these drops panic
+                        for drop in arg_drops.iter().copied() {
+                            unwind_entry_point = unwind_drops.add_drop(drop, unwind_entry_point);
+                        }
+
+                        unwind_drops.add_entry_point(block, unwind_entry_point);
+
+                        let next = self.cfg.start_new_block();
+                        self.cfg.terminate(
+                            block,
+                            source_info,
+                            TerminatorKind::Drop {
+                                place: local.into(),
+                                target: next,
+                                unwind: UnwindAction::Continue,
+                                replace: false,
+                            },
+                        );
+                        block = next;
+                    }
+                    DropKind::Storage => {
+                        // Only temps and vars need their storage dead.
+                        assert!(local.index() > self.arg_count);
+                        self.cfg.push(
+                            block,
+                            Statement { source_info, kind: StatementKind::StorageDead(local) },
+                        );
+                    }
+                }
+            }
+        }
+
+        block.unit()
+    }
+
     fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
         // If we are emitting a `drop` statement, we need to have the cached
         // diverge cleanup pads ready in case that drop panics.
@@ -1523,6 +1608,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
             | TerminatorKind::UnwindResume
             | TerminatorKind::UnwindTerminate(_)
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::Unreachable
             | TerminatorKind::Yield { .. }
             | TerminatorKind::CoroutineDrop
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index 2c817d605af..263e777d03a 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -141,7 +141,7 @@ impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> {
                 return false;
             };
             let (callee, call_args) = if let Ok(Some(instance)) =
-                Instance::resolve(tcx, param_env, callee, normalized_args)
+                Instance::try_resolve(tcx, param_env, callee, normalized_args)
             {
                 (instance.def_id(), instance.args)
             } else {
@@ -217,12 +217,28 @@ impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor<BasicBlocks<'tcx
             | TerminatorKind::FalseUnwind { .. }
             | TerminatorKind::Goto { .. }
             | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue(()),
+
+            // Note that tail call terminator technically returns to the caller,
+            // but for purposes of this lint it makes sense to count it as possibly recursive,
+            // since it's still a call.
+            //
+            // If this'll be repurposed for something else, this might need to be changed.
+            TerminatorKind::TailCall { .. } => ControlFlow::Continue(()),
         }
     }
 
     fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> {
         // When we examine a node for the last time, remember it if it is a recursive call.
         let terminator = self.body[bb].terminator();
+
+        // FIXME(explicit_tail_calls): highlight tail calls as "recursive call site"
+        //
+        // We don't want to lint functions that recurse only through tail calls
+        // (such as `fn g() { become () }`), so just adding `| TailCall { ... }`
+        // here won't work.
+        //
+        // But at the same time we would like to highlight both calls in a function like
+        // `fn f() { if false { become f() } else { f() } }`, so we need to figure something out.
         if self.classifier.is_recursive_terminator(self.tcx, self.body, terminator) {
             self.reachable_recursive_calls.push(terminator.source_info.span);
         }
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 8c6c9e10cdf..5745dc0969c 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
@@ -138,7 +138,7 @@ impl<'tcx> ConstToPat<'tcx> {
             // lints, but no errors), double-check that all types in the const implement
             // `PartialEq`. Even if we have a valtree, we may have found something
             // in there with non-structural-equality, meaning we match using `PartialEq`
-            // and we hence have to check that that impl exists.
+            // and we hence have to check if that impl exists.
             // This is all messy but not worth cleaning up: at some point we'll emit
             // a hard error when we don't have a valtree or when we find something in
             // the valtree that is not structural; then this can all be made a lot simpler.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 93db1f61853..fd778ef78a3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -558,7 +558,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let args = self
             .tcx
             .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_args(id));
-        let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, args) {
+        let instance = match ty::Instance::try_resolve(self.tcx, param_env_reveal_all, def_id, args)
+        {
             Ok(Some(i)) => i,
             Ok(None) => {
                 // It should be assoc consts if there's no error but we cannot resolve it.
diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
index 1c2b475a43c..23738f7a4a5 100644
--- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
@@ -76,6 +76,8 @@ pub trait MeetSemiLattice: Eq {
 /// A set that has a "bottom" element, which is less than or equal to any other element.
 pub trait HasBottom {
     const BOTTOM: Self;
+
+    fn is_bottom(&self) -> bool;
 }
 
 /// A set that has a "top" element, which is greater than or equal to any other element.
@@ -114,6 +116,10 @@ impl MeetSemiLattice for bool {
 
 impl HasBottom for bool {
     const BOTTOM: Self = false;
+
+    fn is_bottom(&self) -> bool {
+        !self
+    }
 }
 
 impl HasTop for bool {
@@ -267,6 +273,10 @@ impl<T: Clone + Eq> MeetSemiLattice for FlatSet<T> {
 
 impl<T> HasBottom for FlatSet<T> {
     const BOTTOM: Self = Self::Bottom;
+
+    fn is_bottom(&self) -> bool {
+        matches!(self, Self::Bottom)
+    }
 }
 
 impl<T> HasTop for FlatSet<T> {
@@ -291,6 +301,10 @@ impl<T> MaybeReachable<T> {
 
 impl<T> HasBottom for MaybeReachable<T> {
     const BOTTOM: Self = MaybeReachable::Unreachable;
+
+    fn is_bottom(&self) -> bool {
+        matches!(self, Self::Unreachable)
+    }
 }
 
 impl<T: HasTop> HasTop for MaybeReachable<T> {
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 706bb796349..574da949b0e 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -145,6 +145,7 @@ where
             | TerminatorKind::InlineAsm { .. }
             | TerminatorKind::UnwindResume
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::SwitchInt { .. }
             | TerminatorKind::Unreachable
             | TerminatorKind::Yield { .. } => {}
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 29169c31263..f850a710277 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -288,6 +288,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
             | TerminatorKind::Goto { .. }
             | TerminatorKind::UnwindResume
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::SwitchInt { .. }
             | TerminatorKind::Unreachable => {}
         }
@@ -325,6 +326,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
             | TerminatorKind::Goto { .. }
             | TerminatorKind::UnwindResume
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::SwitchInt { .. }
             | TerminatorKind::Unreachable => {}
         }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 1fb77bef3d4..7b39db821d8 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -489,6 +489,12 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
                     self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly);
                 }
             }
+            TerminatorKind::TailCall { ref func, ref args, .. } => {
+                self.gather_operand(func);
+                for arg in args {
+                    self.gather_operand(&arg.node);
+                }
+            }
             TerminatorKind::InlineAsm {
                 template: _,
                 ref operands,
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index bfbfff7e259..1582c2e8a90 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -36,10 +36,10 @@ use std::collections::VecDeque;
 use std::fmt::{Debug, Formatter};
 use std::ops::Range;
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, StdEntry};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_index::bit_set::BitSet;
-use rustc_index::{IndexSlice, IndexVec};
+use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
@@ -269,6 +269,9 @@ pub trait ValueAnalysis<'tcx> {
             TerminatorKind::SwitchInt { discr, targets } => {
                 return self.handle_switch_int(discr, targets, state);
             }
+            TerminatorKind::TailCall { .. } => {
+                // FIXME(explicit_tail_calls): determine if we need to do something here (probably not)
+            }
             TerminatorKind::Goto { .. }
             | TerminatorKind::UnwindResume
             | TerminatorKind::UnwindTerminate(_)
@@ -336,14 +339,13 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper
     const NAME: &'static str = T::NAME;
 
     fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain {
-        State(StateData::Unreachable)
+        State::Unreachable
     }
 
     fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
         // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥.
-        assert!(matches!(state.0, StateData::Unreachable));
-        let values = IndexVec::from_elem_n(T::Value::BOTTOM, self.0.map().value_count);
-        *state = State(StateData::Reachable(values));
+        assert!(matches!(state, State::Unreachable));
+        *state = State::new_reachable();
         for arg in body.args_iter() {
             state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map());
         }
@@ -415,27 +417,54 @@ rustc_index::newtype_index!(
 
 /// See [`State`].
 #[derive(PartialEq, Eq, Debug)]
-enum StateData<V> {
-    Reachable(IndexVec<ValueIndex, V>),
-    Unreachable,
+pub struct StateData<V> {
+    bottom: V,
+    /// This map only contains values that are not `⊥`.
+    map: FxHashMap<ValueIndex, V>,
+}
+
+impl<V: HasBottom> StateData<V> {
+    fn new() -> StateData<V> {
+        StateData { bottom: V::BOTTOM, map: FxHashMap::default() }
+    }
+
+    fn get(&self, idx: ValueIndex) -> &V {
+        self.map.get(&idx).unwrap_or(&self.bottom)
+    }
+
+    fn insert(&mut self, idx: ValueIndex, elem: V) {
+        if elem.is_bottom() {
+            self.map.remove(&idx);
+        } else {
+            self.map.insert(idx, elem);
+        }
+    }
 }
 
 impl<V: Clone> Clone for StateData<V> {
     fn clone(&self) -> Self {
-        match self {
-            Self::Reachable(x) => Self::Reachable(x.clone()),
-            Self::Unreachable => Self::Unreachable,
-        }
+        StateData { bottom: self.bottom.clone(), map: self.map.clone() }
     }
 
     fn clone_from(&mut self, source: &Self) {
-        match (&mut *self, source) {
-            (Self::Reachable(x), Self::Reachable(y)) => {
-                // We go through `raw` here, because `IndexVec` currently has a naive `clone_from`.
-                x.raw.clone_from(&y.raw);
+        self.map.clone_from(&source.map)
+    }
+}
+
+impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for StateData<V> {
+    fn join(&mut self, other: &Self) -> bool {
+        let mut changed = false;
+        #[allow(rustc::potential_query_instability)]
+        for (i, v) in other.map.iter() {
+            match self.map.entry(*i) {
+                StdEntry::Vacant(e) => {
+                    e.insert(v.clone());
+                    changed = true
+                }
+                StdEntry::Occupied(e) => changed |= e.into_mut().join(v),
             }
-            _ => *self = source.clone(),
         }
+        changed
     }
 }
 
@@ -450,33 +479,47 @@ impl<V: Clone> Clone for StateData<V> {
 ///
 /// Flooding means assigning a value (by default `⊤`) to all tracked projections of a given place.
 #[derive(PartialEq, Eq, Debug)]
-pub struct State<V>(StateData<V>);
+pub enum State<V> {
+    Unreachable,
+    Reachable(StateData<V>),
+}
 
 impl<V: Clone> Clone for State<V> {
     fn clone(&self) -> Self {
-        Self(self.0.clone())
+        match self {
+            Self::Reachable(x) => Self::Reachable(x.clone()),
+            Self::Unreachable => Self::Unreachable,
+        }
     }
 
     fn clone_from(&mut self, source: &Self) {
-        self.0.clone_from(&source.0);
+        match (&mut *self, source) {
+            (Self::Reachable(x), Self::Reachable(y)) => {
+                x.clone_from(&y);
+            }
+            _ => *self = source.clone(),
+        }
     }
 }
 
-impl<V: Clone> State<V> {
-    pub fn new(init: V, map: &Map) -> State<V> {
-        let values = IndexVec::from_elem_n(init, map.value_count);
-        State(StateData::Reachable(values))
+impl<V: Clone + HasBottom> State<V> {
+    pub fn new_reachable() -> State<V> {
+        State::Reachable(StateData::new())
     }
 
-    pub fn all(&self, f: impl Fn(&V) -> bool) -> bool {
-        match self.0 {
-            StateData::Unreachable => true,
-            StateData::Reachable(ref values) => values.iter().all(f),
+    pub fn all_bottom(&self) -> bool {
+        match self {
+            State::Unreachable => false,
+            State::Reachable(ref values) =>
+            {
+                #[allow(rustc::potential_query_instability)]
+                values.map.values().all(V::is_bottom)
+            }
         }
     }
 
     fn is_reachable(&self) -> bool {
-        matches!(&self.0, StateData::Reachable(_))
+        matches!(self, State::Reachable(_))
     }
 
     /// Assign `value` to all places that are contained in `place` or may alias one.
@@ -519,10 +562,8 @@ impl<V: Clone> State<V> {
         map: &Map,
         value: V,
     ) {
-        let StateData::Reachable(values) = &mut self.0 else { return };
-        map.for_each_aliasing_place(place, tail_elem, &mut |vi| {
-            values[vi] = value.clone();
-        });
+        let State::Reachable(values) = self else { return };
+        map.for_each_aliasing_place(place, tail_elem, &mut |vi| values.insert(vi, value.clone()));
     }
 
     /// Low-level method that assigns to a place.
@@ -541,9 +582,9 @@ impl<V: Clone> State<V> {
     ///
     /// The target place must have been flooded before calling this method.
     pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) {
-        let StateData::Reachable(values) = &mut self.0 else { return };
+        let State::Reachable(values) = self else { return };
         if let Some(value_index) = map.places[target].value_index {
-            values[value_index] = value;
+            values.insert(value_index, value)
         }
     }
 
@@ -555,14 +596,14 @@ impl<V: Clone> State<V> {
     ///
     /// The target place must have been flooded before calling this method.
     pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) {
-        let StateData::Reachable(values) = &mut self.0 else { return };
+        let State::Reachable(values) = self else { return };
 
         // If both places are tracked, we copy the value to the target.
         // If the target is tracked, but the source is not, we do nothing, as invalidation has
         // already been performed.
         if let Some(target_value) = map.places[target].value_index {
             if let Some(source_value) = map.places[source].value_index {
-                values[target_value] = values[source_value].clone();
+                values.insert(target_value, values.get(source_value).clone());
             }
         }
         for target_child in map.children(target) {
@@ -616,11 +657,11 @@ impl<V: Clone> State<V> {
 
     /// Retrieve the value stored for a place index, or `None` if it is not tracked.
     pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option<V> {
-        match &self.0 {
-            StateData::Reachable(values) => {
-                map.places[place].value_index.map(|v| values[v].clone())
+        match self {
+            State::Reachable(values) => {
+                map.places[place].value_index.map(|v| values.get(v).clone())
             }
-            StateData::Unreachable => None,
+            State::Unreachable => None,
         }
     }
 
@@ -631,10 +672,10 @@ impl<V: Clone> State<V> {
     where
         V: HasBottom + HasTop,
     {
-        match &self.0 {
-            StateData::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP),
+        match self {
+            State::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP),
             // Because this is unreachable, we can return any value we want.
-            StateData::Unreachable => V::BOTTOM,
+            State::Unreachable => V::BOTTOM,
         }
     }
 
@@ -645,10 +686,10 @@ impl<V: Clone> State<V> {
     where
         V: HasBottom + HasTop,
     {
-        match &self.0 {
-            StateData::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP),
+        match self {
+            State::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP),
             // Because this is unreachable, we can return any value we want.
-            StateData::Unreachable => V::BOTTOM,
+            State::Unreachable => V::BOTTOM,
         }
     }
 
@@ -659,10 +700,10 @@ impl<V: Clone> State<V> {
     where
         V: HasBottom + HasTop,
     {
-        match &self.0 {
-            StateData::Reachable(_) => self.try_get_len(place, map).unwrap_or(V::TOP),
+        match self {
+            State::Reachable(_) => self.try_get_len(place, map).unwrap_or(V::TOP),
             // Because this is unreachable, we can return any value we want.
-            StateData::Unreachable => V::BOTTOM,
+            State::Unreachable => V::BOTTOM,
         }
     }
 
@@ -673,11 +714,11 @@ impl<V: Clone> State<V> {
     where
         V: HasBottom + HasTop,
     {
-        match &self.0 {
-            StateData::Reachable(values) => {
-                map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP)
+        match self {
+            State::Reachable(values) => {
+                map.places[place].value_index.map(|v| values.get(v).clone()).unwrap_or(V::TOP)
             }
-            StateData::Unreachable => {
+            State::Unreachable => {
                 // Because this is unreachable, we can return any value we want.
                 V::BOTTOM
             }
@@ -685,15 +726,15 @@ impl<V: Clone> State<V> {
     }
 }
 
-impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
+impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for State<V> {
     fn join(&mut self, other: &Self) -> bool {
-        match (&mut self.0, &other.0) {
-            (_, StateData::Unreachable) => false,
-            (StateData::Unreachable, _) => {
+        match (&mut *self, other) {
+            (_, State::Unreachable) => false,
+            (State::Unreachable, _) => {
                 *self = other.clone();
                 true
             }
-            (StateData::Reachable(this), StateData::Reachable(other)) => this.join(other),
+            (State::Reachable(this), State::Reachable(ref other)) => this.join(other),
         }
     }
 }
@@ -1194,9 +1235,9 @@ where
     T::Value: Debug,
 {
     fn fmt_with(&self, ctxt: &ValueAnalysisWrapper<T>, f: &mut Formatter<'_>) -> std::fmt::Result {
-        match &self.0 {
-            StateData::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f),
-            StateData::Unreachable => write!(f, "unreachable"),
+        match self {
+            State::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f),
+            State::Unreachable => write!(f, "unreachable"),
         }
     }
 
@@ -1206,8 +1247,8 @@ where
         ctxt: &ValueAnalysisWrapper<T>,
         f: &mut Formatter<'_>,
     ) -> std::fmt::Result {
-        match (&self.0, &old.0) {
-            (StateData::Reachable(this), StateData::Reachable(old)) => {
+        match (self, old) {
+            (State::Reachable(this), State::Reachable(old)) => {
                 debug_with_context(this, Some(old), ctxt.0.map(), f)
             }
             _ => Ok(()), // Consider printing something here.
@@ -1215,21 +1256,21 @@ where
     }
 }
 
-fn debug_with_context_rec<V: Debug + Eq>(
+fn debug_with_context_rec<V: Debug + Eq + HasBottom>(
     place: PlaceIndex,
     place_str: &str,
-    new: &IndexSlice<ValueIndex, V>,
-    old: Option<&IndexSlice<ValueIndex, V>>,
+    new: &StateData<V>,
+    old: Option<&StateData<V>>,
     map: &Map,
     f: &mut Formatter<'_>,
 ) -> std::fmt::Result {
     if let Some(value) = map.places[place].value_index {
         match old {
-            None => writeln!(f, "{}: {:?}", place_str, new[value])?,
+            None => writeln!(f, "{}: {:?}", place_str, new.get(value))?,
             Some(old) => {
-                if new[value] != old[value] {
-                    writeln!(f, "\u{001f}-{}: {:?}", place_str, old[value])?;
-                    writeln!(f, "\u{001f}+{}: {:?}", place_str, new[value])?;
+                if new.get(value) != old.get(value) {
+                    writeln!(f, "\u{001f}-{}: {:?}", place_str, old.get(value))?;
+                    writeln!(f, "\u{001f}+{}: {:?}", place_str, new.get(value))?;
                 }
             }
         }
@@ -1261,9 +1302,9 @@ fn debug_with_context_rec<V: Debug + Eq>(
     Ok(())
 }
 
-fn debug_with_context<V: Debug + Eq>(
-    new: &IndexSlice<ValueIndex, V>,
-    old: Option<&IndexSlice<ValueIndex, V>>,
+fn debug_with_context<V: Debug + Eq + HasBottom>(
+    new: &StateData<V>,
+    old: Option<&StateData<V>>,
     map: &Map,
     f: &mut Formatter<'_>,
 ) -> std::fmt::Result {
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 05674792426..261dcd52d71 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -58,7 +58,7 @@ use crate::deref_separator::deref_finder;
 use crate::errors;
 use crate::pass_manager as pm;
 use crate::simplify;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::pluralize;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
@@ -81,8 +81,8 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::PanicStrategy;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
 use rustc_trait_selection::infer::TyCtxtInferExt as _;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 use std::{iter, ops};
@@ -208,11 +208,8 @@ const UNRESUMED: usize = CoroutineArgs::UNRESUMED;
 const RETURNED: usize = CoroutineArgs::RETURNED;
 /// Coroutine has panicked and is poisoned.
 const POISONED: usize = CoroutineArgs::POISONED;
-
-/// Number of variants to reserve in coroutine state. Corresponds to
-/// `UNRESUMED` (beginning of a coroutine) and `RETURNED`/`POISONED`
-/// (end of a coroutine) states.
-const RESERVED_VARIANTS: usize = 3;
+/// Number of reserved variants of coroutine state.
+const RESERVED_VARIANTS: usize = CoroutineArgs::RESERVED_VARIANTS;
 
 /// A `yield` point in the coroutine.
 struct SuspensionPoint<'tcx> {
@@ -236,8 +233,7 @@ struct TransformVisitor<'tcx> {
     discr_ty: Ty<'tcx>,
 
     // Mapping from Local to (type of local, coroutine struct index)
-    // FIXME(eddyb) This should use `IndexVec<Local, Option<_>>`.
-    remap: FxHashMap<Local, (Ty<'tcx>, VariantIdx, FieldIdx)>,
+    remap: IndexVec<Local, Option<(Ty<'tcx>, VariantIdx, FieldIdx)>>,
 
     // A map from a suspension point in a block to the locals which have live storage at that point
     storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
@@ -485,7 +481,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
     }
 
     fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
-        assert_eq!(self.remap.get(local), None);
+        assert!(!self.remap.contains(*local));
     }
 
     fn visit_place(
@@ -495,7 +491,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
         _location: Location,
     ) {
         // Replace an Local in the remap with a coroutine struct access
-        if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) {
+        if let Some(&Some((ty, variant_index, idx))) = self.remap.get(place.local) {
             replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
         }
     }
@@ -504,7 +500,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
         // Remove StorageLive and StorageDead statements for remapped locals
         data.retain_statements(|s| match s.kind {
             StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
-                !self.remap.contains_key(&l)
+                !self.remap.contains(l)
             }
             _ => true,
         });
@@ -529,13 +525,9 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
 
                 // The resume arg target location might itself be remapped if its base local is
                 // live across a yield.
-                let resume_arg =
-                    if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) {
-                        replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx);
-                        resume_arg
-                    } else {
-                        resume_arg
-                    };
+                if let Some(&Some((ty, variant, idx))) = self.remap.get(resume_arg.local) {
+                    replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx);
+                }
 
                 let storage_liveness: GrowableBitSet<Local> =
                     self.storage_liveness[block].clone().unwrap().into();
@@ -543,7 +535,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
                 for i in 0..self.always_live_locals.domain_size() {
                     let l = Local::new(i);
                     let needs_storage_dead = storage_liveness.contains(l)
-                        && !self.remap.contains_key(&l)
+                        && !self.remap.contains(l)
                         && !self.always_live_locals.contains(l);
                     if needs_storage_dead {
                         data.statements
@@ -1037,7 +1029,7 @@ fn compute_layout<'tcx>(
     liveness: LivenessInfo,
     body: &Body<'tcx>,
 ) -> (
-    FxHashMap<Local, (Ty<'tcx>, VariantIdx, FieldIdx)>,
+    IndexVec<Local, Option<(Ty<'tcx>, VariantIdx, FieldIdx)>>,
     CoroutineLayout<'tcx>,
     IndexVec<BasicBlock, Option<BitSet<Local>>>,
 ) {
@@ -1098,7 +1090,7 @@ fn compute_layout<'tcx>(
     // Create a map from local indices to coroutine struct indices.
     let mut variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, CoroutineSavedLocal>> =
         iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect();
-    let mut remap = FxHashMap::default();
+    let mut remap = IndexVec::from_elem_n(None, saved_locals.domain_size());
     for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() {
         let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx);
         let mut fields = IndexVec::new();
@@ -1109,7 +1101,7 @@ fn compute_layout<'tcx>(
             // around inside coroutines, so it doesn't matter which variant
             // index we access them by.
             let idx = FieldIdx::from_usize(idx);
-            remap.entry(locals[saved_local]).or_insert((tys[saved_local].ty, variant_index, idx));
+            remap[locals[saved_local]] = Some((tys[saved_local].ty, variant_index, idx));
         }
         variant_fields.push(fields);
         variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]);
@@ -1121,7 +1113,9 @@ fn compute_layout<'tcx>(
     for var in &body.var_debug_info {
         let VarDebugInfoContents::Place(place) = &var.value else { continue };
         let Some(local) = place.as_local() else { continue };
-        let Some(&(_, variant, field)) = remap.get(&local) else { continue };
+        let Some(&Some((_, variant, field))) = remap.get(local) else {
+            continue;
+        };
 
         let saved_local = variant_fields[variant][field];
         field_names.get_or_insert_with(saved_local, || var.name);
@@ -1373,6 +1367,10 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
             | TerminatorKind::Call { .. }
             | TerminatorKind::InlineAsm { .. }
             | TerminatorKind::Assert { .. } => return true,
+
+            TerminatorKind::TailCall { .. } => {
+                unreachable!("tail calls can't be present in generators")
+            }
         }
     }
 
@@ -1524,7 +1522,7 @@ fn create_cases<'tcx>(
                 for i in 0..(body.local_decls.len()) {
                     let l = Local::new(i);
                     let needs_storage_live = point.storage_liveness.contains(l)
-                        && !transform.remap.contains_key(&l)
+                        && !transform.remap.contains(l)
                         && !transform.always_live_locals.contains(l);
                     if needs_storage_live {
                         statements
@@ -1922,6 +1920,7 @@ impl<'tcx> Visitor<'tcx> for EnsureCoroutineFieldAssignmentsNeverAlias<'_> {
             | TerminatorKind::UnwindResume
             | TerminatorKind::UnwindTerminate(_)
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::Unreachable
             | TerminatorKind::Drop { .. }
             | TerminatorKind::Assert { .. }
diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs
index 7e401b5482f..a1c1422912e 100644
--- a/compiler/rustc_mir_transform/src/cost_checker.rs
+++ b/compiler/rustc_mir_transform/src/cost_checker.rs
@@ -31,6 +31,39 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> {
         CostChecker { tcx, param_env, callee_body, instance, penalty: 0, bonus: 0 }
     }
 
+    /// Add function-level costs not well-represented by the block-level costs.
+    ///
+    /// Needed because the `CostChecker` is used sometimes for just blocks,
+    /// and even the full `Inline` doesn't call `visit_body`, so there's nowhere
+    /// to put this logic in the visitor.
+    pub fn add_function_level_costs(&mut self) {
+        fn is_call_like(bbd: &BasicBlockData<'_>) -> bool {
+            use TerminatorKind::*;
+            match bbd.terminator().kind {
+                Call { .. } | TailCall { .. } | Drop { .. } | Assert { .. } | InlineAsm { .. } => {
+                    true
+                }
+
+                Goto { .. }
+                | SwitchInt { .. }
+                | UnwindResume
+                | UnwindTerminate(_)
+                | Return
+                | Unreachable => false,
+
+                Yield { .. } | CoroutineDrop | FalseEdge { .. } | FalseUnwind { .. } => {
+                    unreachable!()
+                }
+            }
+        }
+
+        // If the only has one Call (or similar), inlining isn't increasing the total
+        // number of calls, so give extra encouragement to inlining that.
+        if self.callee_body.basic_blocks.iter().filter(|bbd| is_call_like(bbd)).count() == 1 {
+            self.bonus += CALL_PENALTY;
+        }
+    }
+
     pub fn cost(&self) -> usize {
         usize::saturating_sub(self.penalty, self.bonus)
     }
@@ -106,6 +139,9 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
                     self.penalty += LANDINGPAD_PENALTY;
                 }
             }
+            TerminatorKind::TailCall { .. } => {
+                self.penalty += CALL_PENALTY;
+            }
             TerminatorKind::SwitchInt { discr, targets } => {
                 if discr.constant().is_some() {
                     // Not only will this become a `Goto`, but likely other
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 360dccb240d..83fb9ff9743 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -358,9 +358,12 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
         }
 
         // These terminators have no coverage-relevant successors.
-        CoroutineDrop | Return | Unreachable | UnwindResume | UnwindTerminate(_) => {
-            CoverageSuccessors::NotChainable(&[])
-        }
+        CoroutineDrop
+        | Return
+        | TailCall { .. }
+        | Unreachable
+        | UnwindResume
+        | UnwindTerminate(_) => CoverageSuccessors::NotChainable(&[]),
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index 235992ac547..25297245172 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -3,7 +3,9 @@ use std::collections::BTreeSet;
 use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
-use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind};
+use rustc_middle::mir::coverage::{
+    BlockMarkerId, BranchSpan, ConditionInfo, CoverageInfoHi, CoverageKind,
+};
 use rustc_middle::mir::{self, BasicBlock, StatementKind};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
@@ -157,12 +159,12 @@ impl ExtractedMappings {
 }
 
 fn resolve_block_markers(
-    branch_info: &mir::coverage::BranchInfo,
+    coverage_info_hi: &CoverageInfoHi,
     mir_body: &mir::Body<'_>,
 ) -> IndexVec<BlockMarkerId, Option<BasicBlock>> {
     let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
         None,
-        branch_info.num_block_markers,
+        coverage_info_hi.num_block_markers,
     );
 
     // Fill out the mapping from block marker IDs to their enclosing blocks.
@@ -188,11 +190,11 @@ pub(super) fn extract_branch_pairs(
     hir_info: &ExtractedHirInfo,
     basic_coverage_blocks: &CoverageGraph,
 ) -> Vec<BranchPair> {
-    let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] };
+    let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return vec![] };
 
-    let block_markers = resolve_block_markers(branch_info, mir_body);
+    let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
 
-    branch_info
+    coverage_info_hi
         .branch_spans
         .iter()
         .filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| {
@@ -222,9 +224,9 @@ pub(super) fn extract_mcdc_mappings(
     mcdc_branches: &mut impl Extend<MCDCBranch>,
     mcdc_decisions: &mut impl Extend<MCDCDecision>,
 ) {
-    let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return };
+    let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return };
 
-    let block_markers = resolve_block_markers(branch_info, mir_body);
+    let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
 
     let bcb_from_marker =
         |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
@@ -243,7 +245,7 @@ pub(super) fn extract_mcdc_mappings(
             Some((span, true_bcb, false_bcb))
         };
 
-    mcdc_branches.extend(branch_info.mcdc_branch_spans.iter().filter_map(
+    mcdc_branches.extend(coverage_info_hi.mcdc_branch_spans.iter().filter_map(
         |&mir::coverage::MCDCBranchSpan {
              span: raw_span,
              condition_info,
@@ -257,7 +259,7 @@ pub(super) fn extract_mcdc_mappings(
         },
     ));
 
-    mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map(
+    mcdc_decisions.extend(coverage_info_hi.mcdc_decision_spans.iter().filter_map(
         |decision: &mir::coverage::MCDCDecisionSpan| {
             let span = unexpand_into_body_span(decision.span, body_span)?;
 
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index d55bde311c1..2efca40d180 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -8,6 +8,10 @@ mod spans;
 mod tests;
 mod unexpand;
 
+use rustc_hir as hir;
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::coverage::{
     CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind,
 };
@@ -465,6 +469,9 @@ struct ExtractedHirInfo {
     /// Must have the same context and filename as the body span.
     fn_sig_span_extended: Option<Span>,
     body_span: Span,
+    /// "Holes" are regions within the body span that should not be included in
+    /// coverage spans for this function (e.g. closures and nested items).
+    hole_spans: Vec<Span>,
 }
 
 fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo {
@@ -480,7 +487,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
 
     let mut body_span = hir_body.value.span;
 
-    use rustc_hir::{Closure, Expr, ExprKind, Node};
+    use hir::{Closure, Expr, ExprKind, Node};
     // Unexpand a closure's body span back to the context of its declaration.
     // This helps with closure bodies that consist of just a single bang-macro,
     // and also with closure bodies produced by async desugaring.
@@ -507,11 +514,78 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
 
     let function_source_hash = hash_mir_source(tcx, hir_body);
 
-    ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span_extended, body_span }
+    let hole_spans = extract_hole_spans_from_hir(tcx, body_span, hir_body);
+
+    ExtractedHirInfo {
+        function_source_hash,
+        is_async_fn,
+        fn_sig_span_extended,
+        body_span,
+        hole_spans,
+    }
 }
 
-fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
+fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 {
     // FIXME(cjgillot) Stop hashing HIR manually here.
     let owner = hir_body.id().hir_id.owner;
     tcx.hir_owner_nodes(owner).opt_hash_including_bodies.unwrap().to_smaller_hash().as_u64()
 }
+
+fn extract_hole_spans_from_hir<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body_span: Span, // Usually `hir_body.value.span`, but not always
+    hir_body: &hir::Body<'tcx>,
+) -> Vec<Span> {
+    struct HolesVisitor<'hir, F> {
+        hir: Map<'hir>,
+        visit_hole_span: F,
+    }
+
+    impl<'hir, F: FnMut(Span)> Visitor<'hir> for HolesVisitor<'hir, F> {
+        /// - We need `NestedFilter::INTRA = true` so that `visit_item` will be called.
+        /// - Bodies of nested items don't actually get visited, because of the
+        ///   `visit_item` override.
+        /// - For nested bodies that are not part of an item, we do want to visit any
+        ///   items contained within them.
+        type NestedFilter = nested_filter::All;
+
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.hir
+        }
+
+        fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
+            (self.visit_hole_span)(item.span);
+            // Having visited this item, we don't care about its children,
+            // so don't call `walk_item`.
+        }
+
+        // We override `visit_expr` instead of the more specific expression
+        // visitors, so that we have direct access to the expression span.
+        fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
+            match expr.kind {
+                hir::ExprKind::Closure(_) | hir::ExprKind::ConstBlock(_) => {
+                    (self.visit_hole_span)(expr.span);
+                    // Having visited this expression, we don't care about its
+                    // children, so don't call `walk_expr`.
+                }
+
+                // For other expressions, recursively visit as normal.
+                _ => walk_expr(self, expr),
+            }
+        }
+    }
+
+    let mut hole_spans = vec![];
+    let mut visitor = HolesVisitor {
+        hir: tcx.hir(),
+        visit_hole_span: |hole_span| {
+            // Discard any holes that aren't directly visible within the body span.
+            if body_span.contains(hole_span) && body_span.eq_ctxt(hole_span) {
+                hole_spans.push(hole_span);
+            }
+        },
+    };
+
+    visitor.visit_body(hir_body);
+    hole_spans
+}
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 7612c01c52e..dbc26a2808e 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -8,7 +8,7 @@ use rustc_span::Span;
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
 use crate::coverage::mappings;
 use crate::coverage::spans::from_mir::{
-    extract_covspans_and_holes_from_mir, ExtractedCovspans, Hole, SpanFromMir,
+    extract_covspans_from_mir, ExtractedCovspans, Hole, SpanFromMir,
 };
 use crate::coverage::ExtractedHirInfo;
 
@@ -20,8 +20,8 @@ pub(super) fn extract_refined_covspans(
     basic_coverage_blocks: &CoverageGraph,
     code_mappings: &mut impl Extend<mappings::CodeMapping>,
 ) {
-    let ExtractedCovspans { mut covspans, mut holes } =
-        extract_covspans_and_holes_from_mir(mir_body, hir_info, basic_coverage_blocks);
+    let ExtractedCovspans { mut covspans } =
+        extract_covspans_from_mir(mir_body, hir_info, basic_coverage_blocks);
 
     // First, perform the passes that need macro information.
     covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb));
@@ -45,6 +45,7 @@ pub(super) fn extract_refined_covspans(
     covspans.dedup_by(|b, a| a.span.source_equal(b.span));
 
     // Sort the holes, and merge overlapping/adjacent holes.
+    let mut holes = hir_info.hole_spans.iter().map(|&span| Hole { span }).collect::<Vec<_>>();
     holes.sort_by(|a, b| compare_spans(a.span, b.span));
     holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b));
 
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 2ca166929ee..32bd25bf4b9 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -1,8 +1,7 @@
 use rustc_middle::bug;
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::{
-    self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
-    TerminatorKind,
+    self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind,
 };
 use rustc_span::{Span, Symbol};
 
@@ -15,13 +14,12 @@ use crate::coverage::ExtractedHirInfo;
 
 pub(crate) struct ExtractedCovspans {
     pub(crate) covspans: Vec<SpanFromMir>,
-    pub(crate) holes: Vec<Hole>,
 }
 
 /// Traverses the MIR body to produce an initial collection of coverage-relevant
 /// spans, each associated with a node in the coverage graph (BCB) and possibly
 /// other metadata.
-pub(crate) fn extract_covspans_and_holes_from_mir(
+pub(crate) fn extract_covspans_from_mir(
     mir_body: &mir::Body<'_>,
     hir_info: &ExtractedHirInfo,
     basic_coverage_blocks: &CoverageGraph,
@@ -29,21 +27,13 @@ pub(crate) fn extract_covspans_and_holes_from_mir(
     let &ExtractedHirInfo { body_span, .. } = hir_info;
 
     let mut covspans = vec![];
-    let mut holes = vec![];
 
     for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
-        bcb_to_initial_coverage_spans(
-            mir_body,
-            body_span,
-            bcb,
-            bcb_data,
-            &mut covspans,
-            &mut holes,
-        );
+        bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data, &mut covspans);
     }
 
     // Only add the signature span if we found at least one span in the body.
-    if !covspans.is_empty() || !holes.is_empty() {
+    if !covspans.is_empty() {
         // If there is no usable signature span, add a fake one (before refinement)
         // to avoid an ugly gap between the body start and the first real span.
         // FIXME: Find a more principled way to solve this problem.
@@ -51,7 +41,7 @@ pub(crate) fn extract_covspans_and_holes_from_mir(
         covspans.push(SpanFromMir::for_fn_sig(fn_sig_span));
     }
 
-    ExtractedCovspans { covspans, holes }
+    ExtractedCovspans { covspans }
 }
 
 // Generate a set of coverage spans from the filtered set of `Statement`s and `Terminator`s of
@@ -65,7 +55,6 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
     bcb: BasicCoverageBlock,
     bcb_data: &'a BasicCoverageBlockData,
     initial_covspans: &mut Vec<SpanFromMir>,
-    holes: &mut Vec<Hole>,
 ) {
     for &bb in &bcb_data.basic_blocks {
         let data = &mir_body[bb];
@@ -81,13 +70,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
             let expn_span = filtered_statement_span(statement)?;
             let (span, visible_macro) = unexpand(expn_span)?;
 
-            // A statement that looks like the assignment of a closure expression
-            // is treated as a "hole" span, to be carved out of other spans.
-            if is_closure_like(statement) {
-                holes.push(Hole { span });
-            } else {
-                initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb));
-            }
+            initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb));
             Some(())
         };
         for statement in data.statements.iter() {
@@ -105,18 +88,6 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
     }
 }
 
-fn is_closure_like(statement: &Statement<'_>) -> bool {
-    match statement.kind {
-        StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind {
-            AggregateKind::Closure(_, _)
-            | AggregateKind::Coroutine(_, _)
-            | AggregateKind::CoroutineClosure(..) => true,
-            _ => false,
-        },
-        _ => false,
-    }
-}
-
 /// If the MIR `Statement` has a span contributive to computing coverage spans,
 /// return it; otherwise return `None`.
 fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
@@ -193,7 +164,8 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
         | TerminatorKind::Goto { .. } => None,
 
         // Call `func` operand can have a more specific span when part of a chain of calls
-        | TerminatorKind::Call { ref func, .. } => {
+        TerminatorKind::Call { ref func, .. }
+        | TerminatorKind::TailCall { ref func, .. } => {
             let mut span = terminator.source_info.span;
             if let mir::Operand::Constant(box constant) = func {
                 if constant.span.lo() > span.lo() {
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index b1016c0867c..ab73a8af317 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -628,6 +628,12 @@ impl WriteInfo {
                     self.add_operand(&arg.node);
                 }
             }
+            TerminatorKind::TailCall { func, args, .. } => {
+                self.add_operand(func);
+                for arg in args {
+                    self.add_operand(&arg.node);
+                }
+            }
             TerminatorKind::InlineAsm { operands, .. } => {
                 for asm_operand in operands {
                     match asm_operand {
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index fbbb8c5e472..25bebb0539a 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -33,16 +33,16 @@ use std::fmt;
 /// as it would allow running a destructor on a place behind a reference:
 ///
 /// ```text
-// fn drop_term<T>(t: &mut T) {
-//     mir! {
-//         {
-//             Drop(*t, exit)
-//         }
-//         exit = {
-//             Return()
-//         }
-//     }
-// }
+/// fn drop_term<T>(t: &mut T) {
+///     mir! {
+///         {
+///             Drop(*t, exit)
+///         }
+///         exit = {
+///             Return()
+///         }
+///     }
+/// }
 /// ```
 pub struct ElaborateDrops;
 
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 3dbdeb615cf..1002746e553 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -8,7 +8,7 @@
 //! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values.
 //!
 //! From those assignments, we construct a mapping `VnIndex -> Vec<(Local, Location)>` of available
-//! values, the locals in which they are stored, and a the assignment location.
+//! values, the locals in which they are stored, and the assignment location.
 //!
 //! In a second pass, we traverse all (non SSA) assignments `x = rvalue` and operands. For each
 //! one, we compute the `VnIndex` of the rvalue. If this `VnIndex` is associated to a constant, we
@@ -1391,11 +1391,15 @@ fn op_to_prop_const<'tcx>(
         let (prov, offset) = pointer.into_parts();
         let alloc_id = prov.alloc_id();
         intern_const_alloc_for_constprop(ecx, alloc_id).ok()?;
-        if matches!(ecx.tcx.global_alloc(alloc_id), GlobalAlloc::Memory(_)) {
-            // `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything
-            // by `GlobalAlloc::Memory`, so do fall through to copying if needed.
-            // FIXME: find a way to treat this more uniformly
-            // (probably by fixing codegen)
+
+        // `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything
+        // by `GlobalAlloc::Memory`, so do fall through to copying if needed.
+        // FIXME: find a way to treat this more uniformly (probably by fixing codegen)
+        if let GlobalAlloc::Memory(alloc) = ecx.tcx.global_alloc(alloc_id)
+            // Transmuting a constant is just an offset in the allocation. If the alignment of the
+            // allocation is not enough, fallback to copying into a properly aligned value.
+            && alloc.inner().align >= op.layout.align.abi
+        {
             return Some(ConstValue::Indirect { alloc_id, offset });
         }
     }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 07482d0571a..fd9f0fec88d 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -41,6 +41,12 @@ struct CallSite<'tcx> {
 
 impl<'tcx> MirPass<'tcx> for Inline {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined
+        // MIR correctly when Modified Condition/Decision Coverage is enabled.
+        if sess.instrument_coverage_mcdc() {
+            return false;
+        }
+
         if let Some(enabled) = sess.opts.unstable_opts.inline_mir {
             return enabled;
         }
@@ -85,13 +91,18 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
     }
 
     let param_env = tcx.param_env_reveal_all_normalized(def_id);
+    let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
 
     let mut this = Inliner {
         tcx,
         param_env,
-        codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
+        codegen_fn_attrs,
         history: Vec::new(),
         changed: false,
+        caller_is_inline_forwarder: matches!(
+            codegen_fn_attrs.inline,
+            InlineAttr::Hint | InlineAttr::Always
+        ) && body_is_forwarder(body),
     };
     let blocks = START_BLOCK..body.basic_blocks.next_index();
     this.process_blocks(body, blocks);
@@ -111,6 +122,9 @@ struct Inliner<'tcx> {
     history: Vec<DefId>,
     /// Indicates that the caller body has been modified.
     changed: bool,
+    /// Indicates that the caller is #[inline] and just calls another function,
+    /// and thus we can inline less into it as it'll be inlined itself.
+    caller_is_inline_forwarder: bool,
 }
 
 impl<'tcx> Inliner<'tcx> {
@@ -375,13 +389,15 @@ impl<'tcx> Inliner<'tcx> {
     ) -> Option<CallSite<'tcx>> {
         // Only consider direct calls to functions
         let terminator = bb_data.terminator();
+
+        // FIXME(explicit_tail_calls): figure out if we can inline tail calls
         if let TerminatorKind::Call { ref func, fn_span, .. } = terminator.kind {
             let func_ty = func.ty(caller_body, self.tcx);
             if let ty::FnDef(def_id, args) = *func_ty.kind() {
                 // To resolve an instance its args have to be fully normalized.
                 let args = self.tcx.try_normalize_erasing_regions(self.param_env, args).ok()?;
                 let callee =
-                    Instance::resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?;
+                    Instance::try_resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?;
 
                 if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def {
                     return None;
@@ -485,7 +501,9 @@ impl<'tcx> Inliner<'tcx> {
     ) -> Result<(), &'static str> {
         let tcx = self.tcx;
 
-        let mut threshold = if cross_crate_inlinable {
+        let mut threshold = if self.caller_is_inline_forwarder {
+            self.tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30)
+        } else if cross_crate_inlinable {
             self.tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100)
         } else {
             self.tcx.sess.opts.unstable_opts.inline_mir_threshold.unwrap_or(50)
@@ -504,6 +522,8 @@ impl<'tcx> Inliner<'tcx> {
         let mut checker =
             CostChecker::new(self.tcx, self.param_env, Some(callsite.callee), callee_body);
 
+        checker.add_function_level_costs();
+
         // Traverse the MIR manually so we can account for the effects of inlining on the CFG.
         let mut work_list = vec![START_BLOCK];
         let mut visited = BitSet::new_empty(callee_body.basic_blocks.len());
@@ -538,6 +558,9 @@ impl<'tcx> Inliner<'tcx> {
                 // inline-asm is detected. LLVM will still possibly do an inline later on
                 // if the no-attribute function ends up with the same instruction set anyway.
                 return Err("Cannot move inline-asm across instruction sets");
+            } else if let TerminatorKind::TailCall { .. } = term.kind {
+                // FIXME(explicit_tail_calls): figure out how exactly functions containing tail calls can be inlined (and if they even should)
+                return Err("can't inline functions with tail calls");
             } else {
                 work_list.extend(term.successors())
             }
@@ -1026,6 +1049,10 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
                 *target = self.map_block(*target);
                 *unwind = self.map_unwind(*unwind);
             }
+            TerminatorKind::TailCall { .. } => {
+                // check_mir_body forbids tail calls
+                unreachable!()
+            }
             TerminatorKind::Call { ref mut target, ref mut unwind, .. } => {
                 if let Some(ref mut tgt) = *target {
                     *tgt = self.map_block(*tgt);
@@ -1091,3 +1118,37 @@ fn try_instance_mir<'tcx>(
     }
     Ok(tcx.instance_mir(instance))
 }
+
+fn body_is_forwarder(body: &Body<'_>) -> bool {
+    let TerminatorKind::Call { target, .. } = body.basic_blocks[START_BLOCK].terminator().kind
+    else {
+        return false;
+    };
+    if let Some(target) = target {
+        let TerminatorKind::Return = body.basic_blocks[target].terminator().kind else {
+            return false;
+        };
+    }
+
+    let max_blocks = if !body.is_polymorphic {
+        2
+    } else if target.is_none() {
+        3
+    } else {
+        4
+    };
+    if body.basic_blocks.len() > max_blocks {
+        return false;
+    }
+
+    body.basic_blocks.iter_enumerated().all(|(bb, bb_data)| {
+        bb == START_BLOCK
+            || matches!(
+                bb_data.terminator().kind,
+                TerminatorKind::Return
+                    | TerminatorKind::Drop { .. }
+                    | TerminatorKind::UnwindResume
+                    | TerminatorKind::UnwindTerminate(_)
+            )
+    })
+}
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 35bcd24ce95..d4477563e3a 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -53,7 +53,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
                 trace!(?caller, ?param_env, ?args, "cannot normalize, skipping");
                 continue;
             };
-            let Ok(Some(callee)) = ty::Instance::resolve(tcx, param_env, callee, args) else {
+            let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, param_env, callee, args) else {
                 trace!(?callee, "cannot resolve, skipping");
                 continue;
             };
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 27e506a920b..97ec0cb39de 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -47,6 +47,7 @@ use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, ScalarInt, TyCtxt};
+use rustc_mir_dataflow::lattice::HasBottom;
 use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem};
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{TagEncoding, Variants};
@@ -158,9 +159,17 @@ impl Condition {
     }
 }
 
-#[derive(Copy, Clone, Debug, Default)]
+#[derive(Copy, Clone, Debug)]
 struct ConditionSet<'a>(&'a [Condition]);
 
+impl HasBottom for ConditionSet<'_> {
+    const BOTTOM: Self = ConditionSet(&[]);
+
+    fn is_bottom(&self) -> bool {
+        self.0.is_empty()
+    }
+}
+
 impl<'a> ConditionSet<'a> {
     fn iter(self) -> impl Iterator<Item = Condition> + 'a {
         self.0.iter().copied()
@@ -177,7 +186,7 @@ impl<'a> ConditionSet<'a> {
 
 impl<'tcx, 'a> TOFinder<'tcx, 'a> {
     fn is_empty(&self, state: &State<ConditionSet<'a>>) -> bool {
-        state.all(|cs| cs.0.is_empty())
+        state.all_bottom()
     }
 
     /// Recursion entry point to find threading opportunities.
@@ -198,7 +207,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
         debug!(?discr);
 
         let cost = CostChecker::new(self.tcx, self.param_env, None, self.body);
-        let mut state = State::new(ConditionSet::default(), self.map);
+        let mut state = State::new_reachable();
 
         let conds = if let Some((value, then, else_)) = targets.as_static_if() {
             let value = ScalarInt::try_from_uint(value, discr_layout.size)?;
@@ -255,7 +264,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
             //   _1 = 5 // Whatever happens here, it won't change the result of a `SwitchInt`.
             //   _1 = 6
             if let Some((lhs, tail)) = self.mutated_statement(stmt) {
-                state.flood_with_tail_elem(lhs.as_ref(), tail, self.map, ConditionSet::default());
+                state.flood_with_tail_elem(lhs.as_ref(), tail, self.map, ConditionSet::BOTTOM);
             }
         }
 
@@ -587,6 +596,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
             TerminatorKind::UnwindResume
             | TerminatorKind::UnwindTerminate(_)
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::Unreachable
             | TerminatorKind::CoroutineDrop => bug!("{term:?} has no terminators"),
             // Disallowed during optimizations.
@@ -609,7 +619,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
         // We can recurse through this terminator.
         let mut state = state();
         if let Some(place_to_flood) = place_to_flood {
-            state.flood_with(place_to_flood.as_ref(), self.map, ConditionSet::default());
+            state.flood_with(place_to_flood.as_ref(), self.map, ConditionSet::BOTTOM);
         }
         self.find_opportunity(bb, state, cost.clone(), depth + 1);
     }
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 8d6c00bbedb..82ad8879d17 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -799,6 +799,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
             | TerminatorKind::UnwindResume
             | TerminatorKind::UnwindTerminate(_)
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::Unreachable
             | TerminatorKind::Drop { .. }
             | TerminatorKind::Yield { .. }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index f7056702cb4..5d253d7384d 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -519,7 +519,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         &add_subtyping_projections::Subtyper, // calling this after reveal_all ensures that we don't deal with opaque types
         &elaborate_drops::ElaborateDrops,
         // This will remove extraneous landing pads which are no longer
-        // necessary as well as well as forcing any call in a non-unwinding
+        // necessary as well as forcing any call in a non-unwinding
         // function calling a possibly-unwinding function to abort the process.
         &abort_unwinding_calls::AbortUnwindingCalls,
         // AddMovesForPackedDrops needs to run after drop
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
index db2bb60bdac..d928d7cf764 100644
--- a/compiler/rustc_mir_transform/src/mentioned_items.rs
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -38,7 +38,7 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
         self.super_terminator(terminator, location);
         let span = || self.body.source_info(location).span;
         match &terminator.kind {
-            mir::TerminatorKind::Call { func, .. } => {
+            mir::TerminatorKind::Call { func, .. } | mir::TerminatorKind::TailCall { func, .. } => {
                 let callee_ty = func.ty(self.body, self.tcx);
                 self.mentioned_items
                     .push(Spanned { node: MentionedItem::Fn(callee_ty), span: span() });
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 3f4d2b65ff2..736647fb64b 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -816,7 +816,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                     mut func, mut args, call_source: desugar, fn_span, ..
                 } => {
                     // This promoted involves a function call, so it may fail to evaluate.
-                    // Let's make sure it is added to `required_consts` so that that failure cannot get lost.
+                    // Let's make sure it is added to `required_consts` so that failure cannot get lost.
                     self.add_to_required = true;
 
                     self.visit_operand(&mut func, loc);
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index fb52bfa468a..1df5737e859 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -75,6 +75,7 @@ impl RemoveNoopLandingPads {
             | TerminatorKind::UnwindTerminate(_)
             | TerminatorKind::Unreachable
             | TerminatorKind::Call { .. }
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::Assert { .. }
             | TerminatorKind::Drop { .. }
             | TerminatorKind::InlineAsm { .. } => false,
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 25577e88e28..6835a39cf36 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -1,18 +1,17 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
+use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
-
-use rustc_index::{Idx, IndexVec};
-
 use rustc_span::{source_map::Spanned, Span, DUMMY_SP};
+use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
 use rustc_target::spec::abi::Abi;
 
+use std::assert_matches::assert_matches;
 use std::fmt;
 use std::iter;
 
@@ -1020,21 +1019,19 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
     receiver_by_ref: bool,
 ) -> Body<'tcx> {
     let mut self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity();
+    let mut self_local: Place<'tcx> = Local::from_usize(1).into();
     let ty::CoroutineClosure(_, args) = *self_ty.kind() else {
         bug!();
     };
 
-    // We use `&mut Self` here because we only need to emit an ABI-compatible shim body,
-    // rather than match the signature exactly (which might take `&self` instead).
+    // We use `&Self` here because we only need to emit an ABI-compatible shim body,
+    // rather than match the signature exactly (which might take `&mut self` instead).
     //
-    // The self type here is a coroutine-closure, not a coroutine, and we never read from
-    // it because it never has any captures, because this is only true in the Fn/FnMut
-    // implementation, not the AsyncFn/AsyncFnMut implementation, which is implemented only
-    // if the coroutine-closure has no captures.
+    // We adjust the `self_local` to be a deref since we want to copy fields out of
+    // a reference to the closure.
     if receiver_by_ref {
-        // Triple-check that there's no captures here.
-        assert_eq!(args.as_coroutine_closure().tupled_upvars_ty(), tcx.types.unit);
-        self_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, self_ty);
+        self_local = tcx.mk_place_deref(self_local);
+        self_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, self_ty);
     }
 
     let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
@@ -1067,11 +1064,27 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
         fields.push(Operand::Move(Local::from_usize(idx + 1).into()));
     }
     for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() {
-        fields.push(Operand::Move(tcx.mk_place_field(
-            Local::from_usize(1).into(),
-            FieldIdx::from_usize(idx),
-            ty,
-        )));
+        if receiver_by_ref {
+            // The only situation where it's possible is when we capture immuatable references,
+            // since those don't need to be reborrowed with the closure's env lifetime. Since
+            // references are always `Copy`, just emit a copy.
+            assert_matches!(
+                ty.kind(),
+                ty::Ref(_, _, hir::Mutability::Not),
+                "field should be captured by immutable ref if we have an `Fn` instance"
+            );
+            fields.push(Operand::Copy(tcx.mk_place_field(
+                self_local,
+                FieldIdx::from_usize(idx),
+                ty,
+            )));
+        } else {
+            fields.push(Operand::Move(tcx.mk_place_field(
+                self_local,
+                FieldIdx::from_usize(idx),
+                ty,
+            )));
+        }
     }
 
     let source_info = SourceInfo::outermost(span);
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 2018a8fe667..ab5c25c4937 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -400,40 +400,44 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
                 self.check_edge(location, *target, EdgeKind::Normal);
                 self.check_unwind_edge(location, *unwind);
             }
-            TerminatorKind::Call { args, destination, target, unwind, .. } => {
-                if let Some(target) = target {
-                    self.check_edge(location, *target, EdgeKind::Normal);
-                }
-                self.check_unwind_edge(location, *unwind);
+            TerminatorKind::Call { args, .. } | TerminatorKind::TailCall { args, .. } => {
+                // FIXME(explicit_tail_calls): refactor this & add tail-call specific checks
+                if let TerminatorKind::Call { target, unwind, destination, .. } = terminator.kind {
+                    if let Some(target) = target {
+                        self.check_edge(location, target, EdgeKind::Normal);
+                    }
+                    self.check_unwind_edge(location, unwind);
+
+                    // The code generation assumes that there are no critical call edges. The assumption
+                    // is used to simplify inserting code that should be executed along the return edge
+                    // from the call. FIXME(tmiasko): Since this is a strictly code generation concern,
+                    // the code generation should be responsible for handling it.
+                    if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Optimized)
+                        && self.is_critical_call_edge(target, unwind)
+                    {
+                        self.fail(
+                            location,
+                            format!(
+                                "encountered critical edge in `Call` terminator {:?}",
+                                terminator.kind,
+                            ),
+                        );
+                    }
 
-                // The code generation assumes that there are no critical call edges. The assumption
-                // is used to simplify inserting code that should be executed along the return edge
-                // from the call. FIXME(tmiasko): Since this is a strictly code generation concern,
-                // the code generation should be responsible for handling it.
-                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Optimized)
-                    && self.is_critical_call_edge(*target, *unwind)
-                {
-                    self.fail(
-                        location,
-                        format!(
-                            "encountered critical edge in `Call` terminator {:?}",
-                            terminator.kind,
-                        ),
-                    );
+                    // The call destination place and Operand::Move place used as an argument might be
+                    // passed by a reference to the callee. Consequently they cannot be packed.
+                    if is_within_packed(self.tcx, &self.body.local_decls, destination).is_some() {
+                        // This is bad! The callee will expect the memory to be aligned.
+                        self.fail(
+                            location,
+                            format!(
+                                "encountered packed place in `Call` terminator destination: {:?}",
+                                terminator.kind,
+                            ),
+                        );
+                    }
                 }
 
-                // The call destination place and Operand::Move place used as an argument might be
-                // passed by a reference to the callee. Consequently they cannot be packed.
-                if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() {
-                    // This is bad! The callee will expect the memory to be aligned.
-                    self.fail(
-                        location,
-                        format!(
-                            "encountered packed place in `Call` terminator destination: {:?}",
-                            terminator.kind,
-                        ),
-                    );
-                }
                 for arg in args {
                     if let Operand::Move(place) = &arg.node {
                         if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() {
@@ -1498,15 +1502,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     }
                 }
             }
-            TerminatorKind::Call { func, .. } => {
+            TerminatorKind::Call { func, .. } | TerminatorKind::TailCall { func, .. } => {
                 let func_ty = func.ty(&self.body.local_decls, self.tcx);
                 match func_ty.kind() {
                     ty::FnPtr(..) | ty::FnDef(..) => {}
                     _ => self.fail(
                         location,
-                        format!("encountered non-callable type {func_ty} in `Call` terminator"),
+                        format!(
+                            "encountered non-callable type {func_ty} in `{}` terminator",
+                            terminator.kind.name()
+                        ),
                     ),
                 }
+
+                if let TerminatorKind::TailCall { .. } = terminator.kind {
+                    // FIXME(explicit_tail_calls): implement tail-call specific checks here (such as signature matching, forbidding closures, etc)
+                }
             }
             TerminatorKind::Assert { cond, .. } => {
                 let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl
index 94b553a07a7..7210701d482 100644
--- a/compiler/rustc_monomorphize/messages.ftl
+++ b/compiler/rustc_monomorphize/messages.ftl
@@ -1,6 +1,3 @@
-monomorphize_consider_type_length_limit =
-    consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate
-
 monomorphize_couldnt_dump_mono_stats =
     unexpected error occurred while dumping monomorphization stats: {$error}
 
@@ -25,8 +22,6 @@ monomorphize_start_not_found = using `fn main` requires the standard library
 
 monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
 
-monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
-
 monomorphize_unknown_cgu_collection_mode =
     unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 235743fccc8..bfd505c0672 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -222,12 +222,12 @@ use rustc_middle::mir::{self, Location, MentionedItem};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
 use rustc_middle::ty::layout::ValidityRequirement;
-use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths};
+use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{
     self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
     TypeVisitableExt, VtblEntry,
 };
-use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::EntryFnType;
 use rustc_session::Limit;
@@ -238,9 +238,7 @@ use rustc_target::abi::Size;
 use std::path::PathBuf;
 use tracing::{debug, instrument, trace};
 
-use crate::errors::{
-    self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit, TypeLengthLimit,
-};
+use crate::errors::{self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit};
 use move_check::MoveCheckState;
 
 #[derive(PartialEq)]
@@ -443,7 +441,6 @@ fn collect_items_rec<'tcx>(
                 recursion_depths,
                 recursion_limit,
             ));
-            check_type_length_limit(tcx, instance);
 
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
                 collect_items_of_instance(
@@ -554,34 +551,6 @@ fn collect_items_rec<'tcx>(
     }
 }
 
-/// Format instance name that is already known to be too long for rustc.
-/// Show only the first 2 types if it is longer than 32 characters to avoid blasting
-/// the user's terminal with thousands of lines of type-name.
-///
-/// If the type name is longer than before+after, it will be written to a file.
-fn shrunk_instance_name<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    instance: Instance<'tcx>,
-) -> (String, Option<PathBuf>) {
-    let s = instance.to_string();
-
-    // Only use the shrunk version if it's really shorter.
-    // This also avoids the case where before and after slices overlap.
-    if s.chars().nth(33).is_some() {
-        let shrunk = format!("{}", ty::ShortInstance(instance, 4));
-        if shrunk == s {
-            return (s, None);
-        }
-
-        let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None);
-        let written_to_path = std::fs::write(&path, s).ok().map(|_| path);
-
-        (shrunk, written_to_path)
-    } else {
-        (s, None)
-    }
-}
-
 fn check_recursion_limit<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
@@ -630,38 +599,6 @@ fn check_recursion_limit<'tcx>(
     (def_id, recursion_depth)
 }
 
-fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
-    let type_length = instance
-        .args
-        .iter()
-        .flat_map(|arg| arg.walk())
-        .filter(|arg| match arg.unpack() {
-            GenericArgKind::Type(_) | GenericArgKind::Const(_) => true,
-            GenericArgKind::Lifetime(_) => false,
-        })
-        .count();
-    debug!(" => type length={}", type_length);
-
-    // Rust code can easily create exponentially-long types using only a
-    // polynomial recursion depth. Even with the default recursion
-    // depth, you can easily get cases that take >2^60 steps to run,
-    // which means that rustc basically hangs.
-    //
-    // Bail out in these cases to avoid that bad user experience.
-    if !tcx.type_length_limit().value_within_limit(type_length) {
-        let (shrunk, written_to_path) = shrunk_instance_name(tcx, instance);
-        let span = tcx.def_span(instance.def_id());
-        let mut path = PathBuf::new();
-        let was_written = if let Some(path2) = written_to_path {
-            path = path2;
-            Some(())
-        } else {
-            None
-        };
-        tcx.dcx().emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length });
-    }
-}
-
 struct MirUsedCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
@@ -818,7 +755,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
         };
 
         match terminator.kind {
-            mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. } => {
+            mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. }
+            | mir::TerminatorKind::TailCall { ref func, ref args, ref fn_span } => {
                 let callee_ty = func.ty(self.body, tcx);
                 // *Before* monomorphizing, record that we already handled this mention.
                 self.used_mentioned_items.insert(MentionedItem::Fn(callee_ty));
@@ -916,7 +854,7 @@ fn visit_fn_use<'tcx>(
 ) {
     if let ty::FnDef(def_id, args) = *ty.kind() {
         let instance = if is_direct_call {
-            ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
+            ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, source)
         } else {
             match ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, args) {
                 Some(instance) => instance,
@@ -1223,10 +1161,10 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
                 });
             }
         }
-        GlobalAlloc::Function(fn_instance) => {
-            if should_codegen_locally(tcx, fn_instance) {
-                trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
-                output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP));
+        GlobalAlloc::Function { instance, .. } => {
+            if should_codegen_locally(tcx, instance) {
+                trace!("collecting {:?} with {:#?}", alloc_id, instance);
+                output.push(create_fn_mono_item(tcx, instance, DUMMY_SP));
             }
         }
         GlobalAlloc::VTable(ty, trait_ref) => {
@@ -1319,7 +1257,7 @@ fn visit_mentioned_item<'tcx>(
         MentionedItem::Fn(ty) => {
             if let ty::FnDef(def_id, args) = *ty.kind() {
                 let instance =
-                    Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args);
+                    Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, span);
                 // `visit_instance_use` was written for "used" item collection but works just as well
                 // for "mentioned" item collection.
                 // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway
@@ -1544,6 +1482,7 @@ impl<'v> RootCollector<'_, 'v> {
             ty::ParamEnv::reveal_all(),
             start_def_id,
             self.tcx.mk_args(&[main_ret_ty.into()]),
+            DUMMY_SP,
         );
 
         self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP));
@@ -1612,9 +1551,10 @@ fn create_mono_items_for_default_impls<'tcx>(
         }
 
         // As mentioned above, the method is legal to eagerly instantiate if it
-        // only has lifetime generic parameters. This is validated by
+        // only has lifetime generic parameters. This is validated by calling
+        // `own_requires_monomorphization` on both the impl and method.
         let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params);
-        let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args);
+        let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP);
 
         let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
         if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) {
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index c0d1efd96c5..9548c46e6fa 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -20,19 +20,6 @@ pub struct RecursionLimit {
 }
 
 #[derive(Diagnostic)]
-#[diag(monomorphize_type_length_limit)]
-#[help(monomorphize_consider_type_length_limit)]
-pub struct TypeLengthLimit {
-    #[primary_span]
-    pub span: Span,
-    pub shrunk: String,
-    #[note(monomorphize_written_to_path)]
-    pub was_written: Option<()>,
-    pub path: PathBuf,
-    pub type_length: usize,
-}
-
-#[derive(Diagnostic)]
 #[diag(monomorphize_no_optimized_mir)]
 pub struct NoOptimizedMir {
     #[note]
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 695d02705ab..82488088e30 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -4,7 +4,8 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::visit::TypeVisitableExt;
 use rustc_type_ir::{
-    self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Interner,
+    self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike,
+    Interner,
 };
 
 use crate::delegate::SolverDelegate;
diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs
new file mode 100644
index 00000000000..55f602d907b
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/coherence.rs
@@ -0,0 +1,469 @@
+use std::fmt::Debug;
+use std::ops::ControlFlow;
+
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor};
+use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
+use tracing::instrument;
+
+/// Whether we do the orphan check relative to this crate or to some remote crate.
+#[derive(Copy, Clone, Debug)]
+pub enum InCrate {
+    Local { mode: OrphanCheckMode },
+    Remote,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum OrphanCheckMode {
+    /// Proper orphan check.
+    Proper,
+    /// Improper orphan check for backward compatibility.
+    ///
+    /// In this mode, type params inside projections are considered to be covered
+    /// even if the projection may normalize to a type that doesn't actually cover
+    /// them. This is unsound. See also [#124559] and [#99554].
+    ///
+    /// [#124559]: https://github.com/rust-lang/rust/issues/124559
+    /// [#99554]: https://github.com/rust-lang/rust/issues/99554
+    Compat,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum Conflict {
+    Upstream,
+    Downstream,
+}
+
+/// Returns whether all impls which would apply to the `trait_ref`
+/// e.g. `Ty: Trait<Arg>` are already known in the local crate.
+///
+/// This both checks whether any downstream or sibling crates could
+/// implement it and whether an upstream crate can add this impl
+/// without breaking backwards compatibility.
+#[instrument(level = "debug", skip(infcx, lazily_normalize_ty), ret)]
+pub fn trait_ref_is_knowable<Infcx, I, E>(
+    infcx: &Infcx,
+    trait_ref: ty::TraitRef<I>,
+    mut lazily_normalize_ty: impl FnMut(I::Ty) -> Result<I::Ty, E>,
+) -> Result<Result<(), Conflict>, E>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+    E: Debug,
+{
+    if orphan_check_trait_ref(infcx, trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok()
+    {
+        // A downstream or cousin crate is allowed to implement some
+        // generic parameters of this trait-ref.
+        return Ok(Err(Conflict::Downstream));
+    }
+
+    if trait_ref_is_local_or_fundamental(infcx.cx(), trait_ref) {
+        // This is a local or fundamental trait, so future-compatibility
+        // is no concern. We know that downstream/cousin crates are not
+        // allowed to implement a generic parameter of this trait ref,
+        // which means impls could only come from dependencies of this
+        // crate, which we already know about.
+        return Ok(Ok(()));
+    }
+
+    // This is a remote non-fundamental trait, so if another crate
+    // can be the "final owner" of the generic parameters of this trait-ref,
+    // they are allowed to implement it future-compatibly.
+    //
+    // However, if we are a final owner, then nobody else can be,
+    // and if we are an intermediate owner, then we don't care
+    // about future-compatibility, which means that we're OK if
+    // we are an owner.
+    if orphan_check_trait_ref(
+        infcx,
+        trait_ref,
+        InCrate::Local { mode: OrphanCheckMode::Proper },
+        &mut lazily_normalize_ty,
+    )?
+    .is_ok()
+    {
+        Ok(Ok(()))
+    } else {
+        Ok(Err(Conflict::Upstream))
+    }
+}
+
+pub fn trait_ref_is_local_or_fundamental<I: Interner>(tcx: I, trait_ref: ty::TraitRef<I>) -> bool {
+    trait_ref.def_id.is_local() || tcx.trait_is_fundamental(trait_ref.def_id)
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum IsFirstInputType {
+    No,
+    Yes,
+}
+
+impl From<bool> for IsFirstInputType {
+    fn from(b: bool) -> IsFirstInputType {
+        match b {
+            false => IsFirstInputType::No,
+            true => IsFirstInputType::Yes,
+        }
+    }
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = "T: Debug"))]
+pub enum OrphanCheckErr<I: Interner, T> {
+    NonLocalInputType(Vec<(I::Ty, IsFirstInputType)>),
+    UncoveredTyParams(UncoveredTyParams<I, T>),
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = "T: Debug"))]
+pub struct UncoveredTyParams<I: Interner, T> {
+    pub uncovered: T,
+    pub local_ty: Option<I::Ty>,
+}
+
+/// Checks whether a trait-ref is potentially implementable by a crate.
+///
+/// The current rule is that a trait-ref orphan checks in a crate C:
+///
+/// 1. Order the parameters in the trait-ref in generic parameters order
+/// - Self first, others linearly (e.g., `<U as Foo<V, W>>` is U < V < W).
+/// 2. Of these type parameters, there is at least one type parameter
+///    in which, walking the type as a tree, you can reach a type local
+///    to C where all types in-between are fundamental types. Call the
+///    first such parameter the "local key parameter".
+///     - e.g., `Box<LocalType>` is OK, because you can visit LocalType
+///       going through `Box`, which is fundamental.
+///     - similarly, `FundamentalPair<Vec<()>, Box<LocalType>>` is OK for
+///       the same reason.
+///     - but (knowing that `Vec<T>` is non-fundamental, and assuming it's
+///       not local), `Vec<LocalType>` is bad, because `Vec<->` is between
+///       the local type and the type parameter.
+/// 3. Before this local type, no generic type parameter of the impl must
+///    be reachable through fundamental types.
+///     - e.g. `impl<T> Trait<LocalType> for Vec<T>` is fine, as `Vec` is not fundamental.
+///     - while `impl<T> Trait<LocalType> for Box<T>` results in an error, as `T` is
+///       reachable through the fundamental type `Box`.
+/// 4. Every type in the local key parameter not known in C, going
+///    through the parameter's type tree, must appear only as a subtree of
+///    a type local to C, with only fundamental types between the type
+///    local to C and the local key parameter.
+///     - e.g., `Vec<LocalType<T>>>` (or equivalently `Box<Vec<LocalType<T>>>`)
+///     is bad, because the only local type with `T` as a subtree is
+///     `LocalType<T>`, and `Vec<->` is between it and the type parameter.
+///     - similarly, `FundamentalPair<LocalType<T>, T>` is bad, because
+///     the second occurrence of `T` is not a subtree of *any* local type.
+///     - however, `LocalType<Vec<T>>` is OK, because `T` is a subtree of
+///     `LocalType<Vec<T>>`, which is local and has no types between it and
+///     the type parameter.
+///
+/// The orphan rules actually serve several different purposes:
+///
+/// 1. They enable link-safety - i.e., 2 mutually-unknowing crates (where
+///    every type local to one crate is unknown in the other) can't implement
+///    the same trait-ref. This follows because it can be seen that no such
+///    type can orphan-check in 2 such crates.
+///
+///    To check that a local impl follows the orphan rules, we check it in
+///    InCrate::Local mode, using type parameters for the "generic" types.
+///
+///    In InCrate::Local mode the orphan check succeeds if the current crate
+///    is definitely allowed to implement the given trait (no false positives).
+///
+/// 2. They ground negative reasoning for coherence. If a user wants to
+///    write both a conditional blanket impl and a specific impl, we need to
+///    make sure they do not overlap. For example, if we write
+///    ```ignore (illustrative)
+///    impl<T> IntoIterator for Vec<T>
+///    impl<T: Iterator> IntoIterator for T
+///    ```
+///    We need to be able to prove that `Vec<$0>: !Iterator` for every type $0.
+///    We can observe that this holds in the current crate, but we need to make
+///    sure this will also hold in all unknown crates (both "independent" crates,
+///    which we need for link-safety, and also child crates, because we don't want
+///    child crates to get error for impl conflicts in a *dependency*).
+///
+///    For that, we only allow negative reasoning if, for every assignment to the
+///    inference variables, every unknown crate would get an orphan error if they
+///    try to implement this trait-ref. To check for this, we use InCrate::Remote
+///    mode. That is sound because we already know all the impls from known crates.
+///
+///    In InCrate::Remote mode the orphan check succeeds if a foreign crate
+///    *could* implement the given trait (no false negatives).
+///
+/// 3. For non-`#[fundamental]` traits, they guarantee that parent crates can
+///    add "non-blanket" impls without breaking negative reasoning in dependent
+///    crates. This is the "rebalancing coherence" (RFC 1023) restriction.
+///
+///    For that, we only allow a crate to perform negative reasoning on
+///    non-local-non-`#[fundamental]` if there's a local key parameter as per (2).
+///
+///    Because we never perform negative reasoning generically (coherence does
+///    not involve type parameters), this can be interpreted as doing the full
+///    orphan check (using InCrate::Local mode), instantiating non-local known
+///    types for all inference variables.
+///
+///    This allows for crates to future-compatibly add impls as long as they
+///    can't apply to types with a key parameter in a child crate - applying
+///    the rules, this basically means that every type parameter in the impl
+///    must appear behind a non-fundamental type (because this is not a
+///    type-system requirement, crate owners might also go for "semantic
+///    future-compatibility" involving things such as sealed traits, but
+///    the above requirement is sufficient, and is necessary in "open world"
+///    cases).
+///
+/// Note that this function is never called for types that have both type
+/// parameters and inference variables.
+#[instrument(level = "trace", skip(infcx, lazily_normalize_ty), ret)]
+pub fn orphan_check_trait_ref<Infcx, I, E: Debug>(
+    infcx: &Infcx,
+    trait_ref: ty::TraitRef<I>,
+    in_crate: InCrate,
+    lazily_normalize_ty: impl FnMut(I::Ty) -> Result<I::Ty, E>,
+) -> Result<Result<(), OrphanCheckErr<I, I::Ty>>, E>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+    E: Debug,
+{
+    if trait_ref.has_param() {
+        panic!("orphan check only expects inference variables: {trait_ref:?}");
+    }
+
+    let mut checker = OrphanChecker::new(infcx, in_crate, lazily_normalize_ty);
+    Ok(match trait_ref.visit_with(&mut checker) {
+        ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
+        ControlFlow::Break(residual) => match residual {
+            OrphanCheckEarlyExit::NormalizationFailure(err) => return Err(err),
+            OrphanCheckEarlyExit::UncoveredTyParam(ty) => {
+                // Does there exist some local type after the `ParamTy`.
+                checker.search_first_local_ty = true;
+                let local_ty = match trait_ref.visit_with(&mut checker) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(local_ty)) => Some(local_ty),
+                    _ => None,
+                };
+                Err(OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
+                    uncovered: ty,
+                    local_ty,
+                }))
+            }
+            OrphanCheckEarlyExit::LocalTy(_) => Ok(()),
+        },
+    })
+}
+
+struct OrphanChecker<'a, Infcx, I: Interner, F> {
+    infcx: &'a Infcx,
+    in_crate: InCrate,
+    in_self_ty: bool,
+    lazily_normalize_ty: F,
+    /// Ignore orphan check failures and exclusively search for the first local type.
+    search_first_local_ty: bool,
+    non_local_tys: Vec<(I::Ty, IsFirstInputType)>,
+}
+
+impl<'a, Infcx, I, F, E> OrphanChecker<'a, Infcx, I, F>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+    F: FnOnce(I::Ty) -> Result<I::Ty, E>,
+{
+    fn new(infcx: &'a Infcx, in_crate: InCrate, lazily_normalize_ty: F) -> Self {
+        OrphanChecker {
+            infcx,
+            in_crate,
+            in_self_ty: true,
+            lazily_normalize_ty,
+            search_first_local_ty: false,
+            non_local_tys: Vec::new(),
+        }
+    }
+
+    fn found_non_local_ty(&mut self, t: I::Ty) -> ControlFlow<OrphanCheckEarlyExit<I, E>> {
+        self.non_local_tys.push((t, self.in_self_ty.into()));
+        ControlFlow::Continue(())
+    }
+
+    fn found_uncovered_ty_param(&mut self, ty: I::Ty) -> ControlFlow<OrphanCheckEarlyExit<I, E>> {
+        if self.search_first_local_ty {
+            return ControlFlow::Continue(());
+        }
+
+        ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty))
+    }
+
+    fn def_id_is_local(&mut self, def_id: I::DefId) -> bool {
+        match self.in_crate {
+            InCrate::Local { .. } => def_id.is_local(),
+            InCrate::Remote => false,
+        }
+    }
+}
+
+enum OrphanCheckEarlyExit<I: Interner, E> {
+    NormalizationFailure(E),
+    UncoveredTyParam(I::Ty),
+    LocalTy(I::Ty),
+}
+
+impl<'a, Infcx, I, F, E> TypeVisitor<I> for OrphanChecker<'a, Infcx, I, F>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+    F: FnMut(I::Ty) -> Result<I::Ty, E>,
+{
+    type Result = ControlFlow<OrphanCheckEarlyExit<I, E>>;
+
+    fn visit_region(&mut self, _r: I::Region) -> Self::Result {
+        ControlFlow::Continue(())
+    }
+
+    fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
+        let ty = self.infcx.shallow_resolve(ty);
+        let ty = match (self.lazily_normalize_ty)(ty) {
+            Ok(norm_ty) if norm_ty.is_ty_var() => ty,
+            Ok(norm_ty) => norm_ty,
+            Err(err) => return ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)),
+        };
+
+        let result = match ty.kind() {
+            ty::Bool
+            | ty::Char
+            | ty::Int(..)
+            | ty::Uint(..)
+            | ty::Float(..)
+            | ty::Str
+            | ty::FnDef(..)
+            | ty::Pat(..)
+            | ty::FnPtr(_)
+            | ty::Array(..)
+            | ty::Slice(..)
+            | ty::RawPtr(..)
+            | ty::Never
+            | ty::Tuple(..) => self.found_non_local_ty(ty),
+
+            ty::Param(..) => panic!("unexpected ty param"),
+
+            ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => {
+                match self.in_crate {
+                    InCrate::Local { .. } => self.found_uncovered_ty_param(ty),
+                    // The inference variable might be unified with a local
+                    // type in that remote crate.
+                    InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+                }
+            }
+
+            // A rigid alias may normalize to anything.
+            // * If it references an infer var, placeholder or bound ty, it may
+            //   normalize to that, so we have to treat it as an uncovered ty param.
+            // * Otherwise it may normalize to any non-type-generic type
+            //   be it local or non-local.
+            ty::Alias(kind, _) => {
+                if ty.has_type_flags(
+                    ty::TypeFlags::HAS_TY_PLACEHOLDER
+                        | ty::TypeFlags::HAS_TY_BOUND
+                        | ty::TypeFlags::HAS_TY_INFER,
+                ) {
+                    match self.in_crate {
+                        InCrate::Local { mode } => match kind {
+                            ty::Projection => {
+                                if let OrphanCheckMode::Compat = mode {
+                                    ControlFlow::Continue(())
+                                } else {
+                                    self.found_uncovered_ty_param(ty)
+                                }
+                            }
+                            _ => self.found_uncovered_ty_param(ty),
+                        },
+                        InCrate::Remote => {
+                            // The inference variable might be unified with a local
+                            // type in that remote crate.
+                            ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                        }
+                    }
+                } else {
+                    // Regarding *opaque types* specifically, we choose to treat them as non-local,
+                    // even those that appear within the same crate. This seems somewhat surprising
+                    // at first, but makes sense when you consider that opaque types are supposed
+                    // to hide the underlying type *within the same crate*. When an opaque type is
+                    // used from outside the module where it is declared, it should be impossible to
+                    // observe anything about it other than the traits that it implements.
+                    //
+                    // The alternative would be to look at the underlying type to determine whether
+                    // or not the opaque type itself should be considered local.
+                    //
+                    // However, this could make it a breaking change to switch the underlying hidden
+                    // type from a local type to a remote type. This would violate the rule that
+                    // opaque types should be completely opaque apart from the traits that they
+                    // implement, so we don't use this behavior.
+                    // Addendum: Moreover, revealing the underlying type is likely to cause cycle
+                    // errors as we rely on coherence / the specialization graph during typeck.
+
+                    self.found_non_local_ty(ty)
+                }
+            }
+
+            // For fundamental types, we just look inside of them.
+            ty::Ref(_, ty, _) => ty.visit_with(self),
+            ty::Adt(def, args) => {
+                if self.def_id_is_local(def.def_id()) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else if def.is_fundamental() {
+                    args.visit_with(self)
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            ty::Foreign(def_id) => {
+                if self.def_id_is_local(def_id) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            ty::Dynamic(tt, ..) => {
+                let principal = tt.principal().map(|p| p.def_id());
+                if principal.is_some_and(|p| self.def_id_is_local(p)) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+            ty::Closure(did, ..) | ty::CoroutineClosure(did, ..) | ty::Coroutine(did, ..) => {
+                if self.def_id_is_local(did) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            // This should only be created when checking whether we have to check whether some
+            // auto trait impl applies. There will never be multiple impls, so we can just
+            // act as if it were a local type here.
+            ty::CoroutineWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+        };
+        // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
+        // the first type we visit is always the self type.
+        self.in_self_ty = false;
+        result
+    }
+
+    /// All possible values for a constant parameter already exist
+    /// in the crate defining the trait, so they are always non-local[^1].
+    ///
+    /// Because there's no way to have an impl where the first local
+    /// generic argument is a constant, we also don't have to fail
+    /// the orphan check when encountering a parameter or a generic constant.
+    ///
+    /// This means that we can completely ignore constants during the orphan check.
+    ///
+    /// See `tests/ui/coherence/const-generics-orphan-check-ok.rs` for examples.
+    ///
+    /// [^1]: This might not hold for function pointers or trait objects in the future.
+    /// As these should be quite rare as const arguments and especially rare as impl
+    /// parameters, allowing uncovered const parameters in impls seems more useful
+    /// than allowing `impl<T> Trait<local_fn_ptr, T> for i32` to compile.
+    fn visit_const(&mut self, _c: I::Const) -> Self::Result {
+        ControlFlow::Continue(())
+    }
+}
diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs
index 6626acfe963..6a3d58b5906 100644
--- a/compiler/rustc_next_trait_solver/src/delegate.rs
+++ b/compiler/rustc_next_trait_solver/src/delegate.rs
@@ -1,18 +1,19 @@
-use std::fmt::Debug;
+use std::ops::Deref;
 
 use rustc_type_ir::fold::TypeFoldable;
-use rustc_type_ir::relate::Relate;
 use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode};
-use rustc_type_ir::{self as ty, Interner};
+use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
 
-pub trait SolverDelegate: Sized {
+pub trait SolverDelegate:
+    Deref<Target: InferCtxtLike<Interner = <Self as SolverDelegate>::Interner>> + Sized
+{
     type Interner: Interner;
-    fn cx(&self) -> Self::Interner;
+    fn cx(&self) -> Self::Interner {
+        (**self).cx()
+    }
 
     type Span: Copy;
 
-    fn solver_mode(&self) -> SolverMode;
-
     fn build_with_canonical<V>(
         cx: Self::Interner,
         solver_mode: SolverMode,
@@ -21,109 +22,21 @@ pub trait SolverDelegate: Sized {
     where
         V: TypeFoldable<Self::Interner>;
 
-    fn universe(&self) -> ty::UniverseIndex;
-    fn create_next_universe(&self) -> ty::UniverseIndex;
-
-    fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
-    fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
-    fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
-
-    fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
-    fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
-
-    fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
-    fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
-    fn opportunistic_resolve_float_var(
-        &self,
-        vid: ty::FloatVid,
-    ) -> <Self::Interner as Interner>::Ty;
-    fn opportunistic_resolve_ct_var(
-        &self,
-        vid: ty::ConstVid,
-    ) -> <Self::Interner as Interner>::Const;
-    fn opportunistic_resolve_effect_var(
-        &self,
-        vid: ty::EffectVid,
-    ) -> <Self::Interner as Interner>::Const;
-    fn opportunistic_resolve_lt_var(
-        &self,
-        vid: ty::RegionVid,
-    ) -> <Self::Interner as Interner>::Region;
-
-    fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
-
-    fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
-    fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
-    fn fresh_args_for_item(
-        &self,
-        def_id: <Self::Interner as Interner>::DefId,
-    ) -> <Self::Interner as Interner>::GenericArgs;
-
     fn fresh_var_for_kind_with_span(
         &self,
         arg: <Self::Interner as Interner>::GenericArg,
         span: Self::Span,
     ) -> <Self::Interner as Interner>::GenericArg;
 
-    fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
-        &self,
-        value: ty::Binder<Self::Interner, T>,
-    ) -> T;
-
-    fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
-        &self,
-        value: ty::Binder<Self::Interner, T>,
-        f: impl FnOnce(T) -> U,
-    ) -> U;
-
-    fn relate<T: Relate<Self::Interner>>(
-        &self,
-        param_env: <Self::Interner as Interner>::ParamEnv,
-        lhs: T,
-        variance: ty::Variance,
-        rhs: T,
-    ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
-
-    fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
-        &self,
-        param_env: <Self::Interner as Interner>::ParamEnv,
-        lhs: T,
-        rhs: T,
-    ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
-
-    fn resolve_vars_if_possible<T>(&self, value: T) -> T
-    where
-        T: TypeFoldable<Self::Interner>;
-
-    fn probe<T>(&self, probe: impl FnOnce() -> T) -> T;
-
     // FIXME: Uplift the leak check into this crate.
     fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>;
 
-    // FIXME: This is only here because elaboration lives in `rustc_infer`!
-    fn elaborate_supertraits(
-        cx: Self::Interner,
-        trait_ref: ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>,
-    ) -> impl Iterator<Item = ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>>;
-
     fn try_const_eval_resolve(
         &self,
         param_env: <Self::Interner as Interner>::ParamEnv,
         unevaluated: ty::UnevaluatedConst<Self::Interner>,
     ) -> Option<<Self::Interner as Interner>::Const>;
 
-    fn sub_regions(
-        &self,
-        sub: <Self::Interner as Interner>::Region,
-        sup: <Self::Interner as Interner>::Region,
-    );
-
-    fn register_ty_outlives(
-        &self,
-        ty: <Self::Interner as Interner>::Ty,
-        r: <Self::Interner as Interner>::Region,
-    );
-
     // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`!
     fn well_formed_goals(
         &self,
@@ -179,14 +92,6 @@ pub trait SolverDelegate: Sized {
 
     fn reset_opaque_types(&self);
 
-    fn trait_ref_is_knowable<E: Debug>(
-        &self,
-        trait_ref: ty::TraitRef<Self::Interner>,
-        lazily_normalize_ty: impl FnMut(
-            <Self::Interner as Interner>::Ty,
-        ) -> Result<<Self::Interner as Interner>::Ty, E>,
-    ) -> Result<bool, E>;
-
     fn fetch_eligible_assoc_item(
         &self,
         param_env: <Self::Interner as Interner>::ParamEnv,
diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs
index a6a9c01faaa..0a5b4278058 100644
--- a/compiler/rustc_next_trait_solver/src/lib.rs
+++ b/compiler/rustc_next_trait_solver/src/lib.rs
@@ -5,6 +5,8 @@
 //! So if you got to this crate from the old solver, it's totally normal.
 
 pub mod canonicalizer;
+pub mod coherence;
 pub mod delegate;
+pub mod relate;
 pub mod resolve;
 pub mod solve;
diff --git a/compiler/rustc_next_trait_solver/src/relate.rs b/compiler/rustc_next_trait_solver/src/relate.rs
new file mode 100644
index 00000000000..db819961bbd
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/relate.rs
@@ -0,0 +1,15 @@
+pub use rustc_type_ir::relate::*;
+
+pub mod combine;
+
+/// Whether aliases should be related structurally or not. Used
+/// to adjust the behavior of generalization and combine.
+///
+/// This should always be `No` unless in a few special-cases when
+/// instantiating canonical responses and in the new solver. Each
+/// such case should have a comment explaining why it is used.
+#[derive(Debug, Copy, Clone)]
+pub enum StructurallyRelateAliases {
+    Yes,
+    No,
+}
diff --git a/compiler/rustc_next_trait_solver/src/relate/combine.rs b/compiler/rustc_next_trait_solver/src/relate/combine.rs
new file mode 100644
index 00000000000..96968327d8e
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/relate/combine.rs
@@ -0,0 +1,34 @@
+pub use rustc_type_ir::relate::*;
+use rustc_type_ir::solve::Goal;
+use rustc_type_ir::{InferCtxtLike, Interner, Upcast};
+
+use super::StructurallyRelateAliases;
+
+pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
+    TypeRelation<I>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
+    fn span(&self) -> I::Span;
+
+    fn param_env(&self) -> I::ParamEnv;
+
+    /// Whether aliases should be related structurally. This is pretty much
+    /// always `No` unless you're equating in some specific locations of the
+    /// new solver. See the comments in these use-cases for more details.
+    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
+
+    /// Register obligations that must hold in order for this relation to hold
+    fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
+
+    /// Register predicates that must hold in order for this relation to hold.
+    /// This uses the default `param_env` of the obligation.
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
+    );
+
+    /// Register `AliasRelate` obligation(s) that both types must be related to each other.
+    fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
+}
diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs
index 6ed58d0e4fb..254ee514f8b 100644
--- a/compiler/rustc_next_trait_solver/src/resolve.rs
+++ b/compiler/rustc_next_trait_solver/src/resolve.rs
@@ -2,7 +2,7 @@ use crate::delegate::SolverDelegate;
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::visit::TypeVisitableExt;
-use rustc_type_ir::{self as ty, Interner};
+use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
 
 ///////////////////////////////////////////////////////////////////////////
 // EAGER RESOLUTION
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 6ee684605ac..01dde9ca587 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -2,6 +2,7 @@
 
 pub(super) mod structural_traits;
 
+use rustc_type_ir::elaborate;
 use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
@@ -387,48 +388,83 @@ where
             G::consider_auto_trait_candidate(self, goal)
         } else if cx.trait_is_alias(trait_def_id) {
             G::consider_trait_alias_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Sized) {
-            G::consider_builtin_sized_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy)
-            || cx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone)
-        {
-            G::consider_builtin_copy_clone_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::PointerLike) {
-            G::consider_builtin_pointer_like_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) {
-            G::consider_builtin_fn_ptr_trait_candidate(self, goal)
-        } else if let Some(kind) = self.cx().fn_trait_kind_from_def_id(trait_def_id) {
-            G::consider_builtin_fn_trait_candidates(self, goal, kind)
-        } else if let Some(kind) = self.cx().async_fn_trait_kind_from_def_id(trait_def_id) {
-            G::consider_builtin_async_fn_trait_candidates(self, goal, kind)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) {
-            G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Tuple) {
-            G::consider_builtin_tuple_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::PointeeTrait) {
-            G::consider_builtin_pointee_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Future) {
-            G::consider_builtin_future_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Iterator) {
-            G::consider_builtin_iterator_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::FusedIterator) {
-            G::consider_builtin_fused_iterator_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncIterator) {
-            G::consider_builtin_async_iterator_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Coroutine) {
-            G::consider_builtin_coroutine_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::DiscriminantKind) {
-            G::consider_builtin_discriminant_kind_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncDestruct) {
-            G::consider_builtin_async_destruct_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Destruct) {
-            G::consider_builtin_destruct_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) {
-            G::consider_builtin_transmute_candidate(self, goal)
-        } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::EffectsIntersection) {
-            G::consider_builtin_effects_intersection_candidate(self, goal)
         } else {
-            Err(NoSolution)
+            match cx.as_lang_item(trait_def_id) {
+                Some(TraitSolverLangItem::Sized) => G::consider_builtin_sized_candidate(self, goal),
+                Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => {
+                    G::consider_builtin_copy_clone_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::Fn) => {
+                    G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
+                }
+                Some(TraitSolverLangItem::FnMut) => {
+                    G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnMut)
+                }
+                Some(TraitSolverLangItem::FnOnce) => {
+                    G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnOnce)
+                }
+                Some(TraitSolverLangItem::AsyncFn) => {
+                    G::consider_builtin_async_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
+                }
+                Some(TraitSolverLangItem::AsyncFnMut) => {
+                    G::consider_builtin_async_fn_trait_candidates(
+                        self,
+                        goal,
+                        ty::ClosureKind::FnMut,
+                    )
+                }
+                Some(TraitSolverLangItem::AsyncFnOnce) => {
+                    G::consider_builtin_async_fn_trait_candidates(
+                        self,
+                        goal,
+                        ty::ClosureKind::FnOnce,
+                    )
+                }
+                Some(TraitSolverLangItem::PointerLike) => {
+                    G::consider_builtin_pointer_like_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::FnPtrTrait) => {
+                    G::consider_builtin_fn_ptr_trait_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::AsyncFnKindHelper) => {
+                    G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::Tuple) => G::consider_builtin_tuple_candidate(self, goal),
+                Some(TraitSolverLangItem::PointeeTrait) => {
+                    G::consider_builtin_pointee_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::Future) => {
+                    G::consider_builtin_future_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::Iterator) => {
+                    G::consider_builtin_iterator_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::FusedIterator) => {
+                    G::consider_builtin_fused_iterator_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::AsyncIterator) => {
+                    G::consider_builtin_async_iterator_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::Coroutine) => {
+                    G::consider_builtin_coroutine_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::DiscriminantKind) => {
+                    G::consider_builtin_discriminant_kind_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::AsyncDestruct) => {
+                    G::consider_builtin_async_destruct_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::Destruct) => {
+                    G::consider_builtin_destruct_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::TransmuteTrait) => {
+                    G::consider_builtin_transmute_candidate(self, goal)
+                }
+                Some(TraitSolverLangItem::EffectsIntersection) => {
+                    G::consider_builtin_effects_intersection_candidate(self, goal)
+                }
+                _ => Err(NoSolution),
+            }
         };
 
         candidates.extend(result);
@@ -632,7 +668,7 @@ where
         // a projection goal.
         if let Some(principal) = bounds.principal() {
             let principal_trait_ref = principal.with_self_ty(cx, self_ty);
-            for (idx, assumption) in D::elaborate_supertraits(cx, principal_trait_ref).enumerate() {
+            for (idx, assumption) in elaborate::supertraits(cx, principal_trait_ref).enumerate() {
                 candidates.extend(G::probe_and_consider_object_bound_candidate(
                     self,
                     CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 3447b39fa5b..7df14e81ab5 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -669,7 +669,9 @@ where
     let cx = ecx.cx();
     let mut requirements = vec![];
     requirements.extend(
-        cx.explicit_super_predicates_of(trait_ref.def_id).iter_instantiated(cx, trait_ref.args),
+        cx.explicit_super_predicates_of(trait_ref.def_id)
+            .iter_instantiated(cx, trait_ref.args)
+            .map(|(pred, _)| pred),
     );
 
     // FIXME(associated_const_equality): Also add associated consts to
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index 0a313c6a951..9474d501d6f 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -14,7 +14,7 @@ use std::iter;
 use rustc_index::IndexVec;
 use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::inherent::*;
-use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner};
+use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner};
 use tracing::{instrument, trace};
 
 use crate::canonicalizer::{CanonicalizeMode, Canonicalizer};
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 87342eefb33..c90f8e76163 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -7,10 +7,11 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::relate::Relate;
 use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
-use rustc_type_ir::{self as ty, CanonicalVarValues, Interner};
+use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use tracing::{instrument, trace};
 
+use crate::coherence;
 use crate::delegate::SolverDelegate;
 use crate::solve::inspect::{self, ProofTreeBuilder};
 use crate::solve::search_graph::SearchGraph;
@@ -906,7 +907,8 @@ where
     ) -> Result<bool, NoSolution> {
         let delegate = self.delegate;
         let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
-        delegate.trait_ref_is_knowable(trait_ref, lazily_normalize_ty)
+        coherence::trait_ref_is_knowable(&**delegate, trait_ref, lazily_normalize_ty)
+            .map(|is_knowable| is_knowable.is_ok())
     }
 
     pub(super) fn fetch_eligible_assoc_item(
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
index e9516c60c70..4258dd9263a 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs
@@ -1,6 +1,6 @@
 use std::marker::PhantomData;
 
-use rustc_type_ir::Interner;
+use rustc_type_ir::{InferCtxtLike, Interner};
 use tracing::instrument;
 
 use crate::delegate::SolverDelegate;
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 24055d6cd83..c65c5851e9b 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -48,12 +48,20 @@ enum GoalEvaluationKind {
     Nested,
 }
 
+// FIXME(trait-system-refactor-initiative#117): we don't detect whether a response
+// ended up pulling down any universes.
 fn has_no_inference_or_external_constraints<I: Interner>(
     response: ty::Canonical<I, Response<I>>,
 ) -> bool {
-    response.value.external_constraints.region_constraints.is_empty()
-        && response.value.var_values.is_identity()
-        && response.value.external_constraints.opaque_types.is_empty()
+    let ExternalConstraintsData {
+        ref region_constraints,
+        ref opaque_types,
+        ref normalization_nested_goals,
+    } = *response.value.external_constraints;
+    response.value.var_values.is_identity()
+        && region_constraints.is_empty()
+        && opaque_types.is_empty()
+        && normalization_nested_goals.is_empty()
 }
 
 impl<'a, D, I> EvalCtxt<'a, D>
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 9275bcc8e97..a83bd689a80 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -3,6 +3,7 @@ mod inherent;
 mod opaque_types;
 mod weak_types;
 
+use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::Upcast as _;
@@ -144,7 +145,7 @@ where
 
         let goal_trait_ref = goal.predicate.alias.trait_ref(cx);
         let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
-        if !ecx.cx().args_may_unify_deep(
+        if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup).args_may_unify(
             goal.predicate.alias.trait_ref(cx).args,
             impl_trait_ref.skip_binder().args,
         ) {
diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
index 2cd3b10f56a..69d52dcad7a 100644
--- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
@@ -71,7 +71,7 @@ struct StackEntry<I: Interner> {
     /// C :- D
     /// D :- C
     /// ```
-    cycle_participants: HashSet<CanonicalInput<I>>,
+    nested_goals: HashSet<CanonicalInput<I>>,
     /// Starts out as `None` and gets set when rerunning this
     /// goal in case we encounter a cycle.
     provisional_result: Option<QueryResult<I>>,
@@ -139,18 +139,11 @@ impl<I: Interner> SearchGraph<I> {
         self.mode
     }
 
-    /// Pops the highest goal from the stack, lazily updating the
-    /// the next goal in the stack.
-    ///
-    /// Directly popping from the stack instead of using this method
-    /// would cause us to not track overflow and recursion depth correctly.
-    fn pop_stack(&mut self) -> StackEntry<I> {
-        let elem = self.stack.pop().unwrap();
-        if let Some(last) = self.stack.raw.last_mut() {
-            last.reached_depth = last.reached_depth.max(elem.reached_depth);
-            last.encountered_overflow |= elem.encountered_overflow;
+    fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) {
+        if let Some(parent) = self.stack.raw.last_mut() {
+            parent.reached_depth = parent.reached_depth.max(reached_depth);
+            parent.encountered_overflow |= encountered_overflow;
         }
-        elem
     }
 
     pub(super) fn is_empty(&self) -> bool {
@@ -222,8 +215,8 @@ impl<I: Interner> SearchGraph<I> {
         let current_cycle_root = &mut stack[current_root.as_usize()];
         for entry in cycle_participants {
             entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head));
-            current_cycle_root.cycle_participants.insert(entry.input);
-            current_cycle_root.cycle_participants.extend(mem::take(&mut entry.cycle_participants));
+            current_cycle_root.nested_goals.insert(entry.input);
+            current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals));
         }
     }
 
@@ -342,7 +335,7 @@ impl<I: Interner> SearchGraph<I> {
                 non_root_cycle_participant: None,
                 encountered_overflow: false,
                 has_been_used: HasBeenUsed::empty(),
-                cycle_participants: Default::default(),
+                nested_goals: Default::default(),
                 provisional_result: None,
             };
             assert_eq!(self.stack.push(entry), depth);
@@ -364,7 +357,7 @@ impl<I: Interner> SearchGraph<I> {
             }
 
             debug!("canonical cycle overflow");
-            let current_entry = self.pop_stack();
+            let current_entry = self.stack.pop().unwrap();
             debug_assert!(current_entry.has_been_used.is_empty());
             let result = Self::response_no_constraints(cx, input, Certainty::overflow(false));
             (current_entry, result)
@@ -372,6 +365,8 @@ impl<I: Interner> SearchGraph<I> {
 
         let proof_tree = inspect.finalize_canonical_goal_evaluation(cx);
 
+        self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow);
+
         // We're now done with this goal. In case this goal is involved in a larger cycle
         // do not remove it from the provisional cache and update its provisional result.
         // We only add the root of cycles to the global cache.
@@ -394,7 +389,7 @@ impl<I: Interner> SearchGraph<I> {
             //
             // We must not use the global cache entry of a root goal if a cycle
             // participant is on the stack. This is necessary to prevent unstable
-            // results. See the comment of `StackEntry::cycle_participants` for
+            // results. See the comment of `StackEntry::nested_goals` for
             // more details.
             self.global_cache(cx).insert(
                 cx,
@@ -402,7 +397,7 @@ impl<I: Interner> SearchGraph<I> {
                 proof_tree,
                 reached_depth,
                 final_entry.encountered_overflow,
-                final_entry.cycle_participants,
+                final_entry.nested_goals,
                 dep_node,
                 result,
             )
@@ -441,14 +436,9 @@ impl<I: Interner> SearchGraph<I> {
             }
         }
 
-        // Update the reached depth of the current goal to make sure
-        // its state is the same regardless of whether we've used the
-        // global cache or not.
+        // Adjust the parent goal as if we actually computed this goal.
         let reached_depth = self.stack.next_index().plus(additional_depth);
-        if let Some(last) = self.stack.raw.last_mut() {
-            last.reached_depth = last.reached_depth.max(reached_depth);
-            last.encountered_overflow |= encountered_overflow;
-        }
+        self.update_parent_goal(reached_depth, encountered_overflow);
 
         Some(result)
     }
@@ -477,7 +467,7 @@ impl<I: Interner> SearchGraph<I> {
         F: FnMut(&mut Self, &mut ProofTreeBuilder<D>) -> QueryResult<I>,
     {
         let result = prove_goal(self, inspect);
-        let stack_entry = self.pop_stack();
+        let stack_entry = self.stack.pop().unwrap();
         debug_assert_eq!(stack_entry.input, input);
 
         // If the current goal is not the root of a cycle, we are done.
@@ -554,27 +544,27 @@ impl<I: Interner> SearchGraph<I> {
                 non_root_cycle_participant,
                 encountered_overflow: _,
                 has_been_used,
-                ref cycle_participants,
+                ref nested_goals,
                 provisional_result,
             } = *entry;
             let cache_entry = provisional_cache.get(&entry.input).unwrap();
             assert_eq!(cache_entry.stack_depth, Some(depth));
             if let Some(head) = non_root_cycle_participant {
                 assert!(head < depth);
-                assert!(cycle_participants.is_empty());
+                assert!(nested_goals.is_empty());
                 assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
 
                 let mut current_root = head;
                 while let Some(parent) = stack[current_root].non_root_cycle_participant {
                     current_root = parent;
                 }
-                assert!(stack[current_root].cycle_participants.contains(&input));
+                assert!(stack[current_root].nested_goals.contains(&input));
             }
 
-            if !cycle_participants.is_empty() {
+            if !nested_goals.is_empty() {
                 assert!(provisional_result.is_some() || !has_been_used.is_empty());
                 for entry in stack.iter().take(depth.as_usize()) {
-                    assert_eq!(cycle_participants.get(&entry.input), None);
+                    assert_eq!(nested_goals.get(&entry.input), None);
                 }
             }
         }
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index f5832f7e5b4..4474bbc2351 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -2,10 +2,11 @@
 
 use rustc_ast_ir::Movability;
 use rustc_type_ir::data_structures::IndexSet;
+use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::visit::TypeVisitableExt as _;
-use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _};
+use rustc_type_ir::{self as ty, elaborate, Interner, TraitPredicate, Upcast as _};
 use tracing::{instrument, trace};
 
 use crate::delegate::SolverDelegate;
@@ -46,7 +47,8 @@ where
         let cx = ecx.cx();
 
         let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
-        if !cx.args_may_unify_deep(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
+        if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup)
+            .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
         {
             return Err(NoSolution);
         }
@@ -785,7 +787,7 @@ where
             ));
         } else if let Some(a_principal) = a_data.principal() {
             for new_a_principal in
-                D::elaborate_supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty)).skip(1)
+                elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty)).skip(1)
             {
                 responses.extend(self.consider_builtin_upcast_to_principal(
                     goal,
@@ -860,8 +862,7 @@ where
             .auto_traits()
             .into_iter()
             .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
-                self.cx()
-                    .supertrait_def_ids(principal_def_id)
+                elaborate::supertrait_def_ids(self.cx(), principal_def_id)
                     .into_iter()
                     .filter(|def_id| self.cx().trait_is_auto(*def_id))
             }))
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index f08efe60d96..e4c75ac1145 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -45,10 +45,6 @@ parse_bad_assoc_type_bounds = bounds on associated types do not belong here
 parse_bad_item_kind = {$descr} is not supported in {$ctx}
     .help = consider moving the {$descr} out to a nearby module scope
 
-parse_bad_return_type_notation_dotdot =
-    return type notation uses `()` instead of `(..)` for elided arguments
-    .suggestion = remove the `..`
-
 parse_bad_return_type_notation_output =
     return type not allowed with return type notation
     .suggestion = remove the return type
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 8d49887f164..6894f470d88 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2568,14 +2568,6 @@ pub(crate) struct BadReturnTypeNotationOutput {
 }
 
 #[derive(Diagnostic)]
-#[diag(parse_bad_return_type_notation_dotdot)]
-pub(crate) struct BadReturnTypeNotationDotDot {
-    #[primary_span]
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(parse_bad_assoc_type_bounds)]
 pub(crate) struct BadAssocTypeBounds {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 58fef9b6c45..a8fe35f45b3 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -282,7 +282,7 @@ impl<'a> Parser<'a> {
     pub fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> {
         let mut attrs = ast::AttrVec::new();
         loop {
-            let start_pos: u32 = self.num_bump_calls.try_into().unwrap();
+            let start_pos = self.num_bump_calls;
             // Only try to parse if it is an inner attribute (has `!`).
             let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) {
                 Some(self.parse_attribute(InnerAttrPolicy::Permitted)?)
@@ -303,7 +303,7 @@ impl<'a> Parser<'a> {
                 None
             };
             if let Some(attr) = attr {
-                let end_pos: u32 = self.num_bump_calls.try_into().unwrap();
+                let end_pos = self.num_bump_calls;
                 // If we are currently capturing tokens, mark the location of this inner attribute.
                 // If capturing ends up creating a `LazyAttrTokenStream`, we will include
                 // this replace range with it, removing the inner attribute from the final
@@ -313,7 +313,7 @@ impl<'a> Parser<'a> {
                 // corresponding macro).
                 let range = start_pos..end_pos;
                 if let Capturing::Yes = self.capture_state.capturing {
-                    self.capture_state.inner_attr_ranges.insert(attr.id, (range, vec![]));
+                    self.capture_state.inner_attr_ranges.insert(attr.id, (range, None));
                 }
                 attrs.push(attr);
             } else {
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index b5480b6b7d2..38f18022e3c 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -1,6 +1,6 @@
 use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken};
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttributesData, DelimSpacing};
+use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing};
 use rustc_ast::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, ToAttrTokenStream};
 use rustc_ast::{self as ast};
 use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens};
@@ -8,7 +8,7 @@ use rustc_errors::PResult;
 use rustc_session::parse::ParseSess;
 use rustc_span::{sym, Span, DUMMY_SP};
 
-use std::ops::Range;
+use std::{iter, mem};
 
 /// A wrapper type to ensure that the parser handles outer attributes correctly.
 /// When we parse outer attributes, we need to ensure that we capture tokens
@@ -29,15 +29,15 @@ pub struct AttrWrapper {
     // The start of the outer attributes in the token cursor.
     // This allows us to create a `ReplaceRange` for the entire attribute
     // target, including outer attributes.
-    start_pos: usize,
+    start_pos: u32,
 }
 
 impl AttrWrapper {
-    pub(super) fn new(attrs: AttrVec, start_pos: usize) -> AttrWrapper {
+    pub(super) fn new(attrs: AttrVec, start_pos: u32) -> AttrWrapper {
         AttrWrapper { attrs, start_pos }
     }
     pub fn empty() -> AttrWrapper {
-        AttrWrapper { attrs: AttrVec::new(), start_pos: usize::MAX }
+        AttrWrapper { attrs: AttrVec::new(), start_pos: u32::MAX }
     }
 
     pub(crate) fn take_for_recovery(self, psess: &ParseSess) -> AttrVec {
@@ -53,7 +53,7 @@ impl AttrWrapper {
     // FIXME: require passing an NT to prevent misuse of this method
     pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) {
         let mut self_attrs = self.attrs;
-        std::mem::swap(attrs, &mut self_attrs);
+        mem::swap(attrs, &mut self_attrs);
         attrs.extend(self_attrs);
     }
 
@@ -87,11 +87,10 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool {
 //
 // This also makes `Parser` very cheap to clone, since
 // there is no intermediate collection buffer to clone.
-#[derive(Clone)]
 struct LazyAttrTokenStreamImpl {
     start_token: (Token, Spacing),
     cursor_snapshot: TokenCursor,
-    num_calls: usize,
+    num_calls: u32,
     break_last_token: bool,
     replace_ranges: Box<[ReplaceRange]>,
 }
@@ -104,15 +103,16 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
         // produce an empty `TokenStream` if no calls were made, and omit the
         // final token otherwise.
         let mut cursor_snapshot = self.cursor_snapshot.clone();
-        let tokens =
-            std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1))
-                .chain(std::iter::repeat_with(|| {
-                    let token = cursor_snapshot.next();
-                    (FlatToken::Token(token.0), token.1)
-                }))
-                .take(self.num_calls);
-
-        if !self.replace_ranges.is_empty() {
+        let tokens = iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1))
+            .chain(iter::repeat_with(|| {
+                let token = cursor_snapshot.next();
+                (FlatToken::Token(token.0), token.1)
+            }))
+            .take(self.num_calls as usize);
+
+        if self.replace_ranges.is_empty() {
+            make_attr_token_stream(tokens, self.break_last_token)
+        } else {
             let mut tokens: Vec<_> = tokens.collect();
             let mut replace_ranges = self.replace_ranges.to_vec();
             replace_ranges.sort_by_key(|(range, _)| range.start);
@@ -144,29 +144,26 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
             // start position, we ensure that any replace range which encloses
             // another replace range will capture the *replaced* tokens for the inner
             // range, not the original tokens.
-            for (range, new_tokens) in replace_ranges.into_iter().rev() {
+            for (range, target) in replace_ranges.into_iter().rev() {
                 assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}");
-                // Replace ranges are only allowed to decrease the number of tokens.
-                assert!(
-                    range.len() >= new_tokens.len(),
-                    "Range {range:?} has greater len than {new_tokens:?}"
-                );
-
-                // Replace any removed tokens with `FlatToken::Empty`.
-                // This keeps the total length of `tokens` constant throughout the
-                // replacement process, allowing us to use all of the `ReplaceRanges` entries
-                // without adjusting indices.
-                let filler = std::iter::repeat((FlatToken::Empty, Spacing::Alone))
-                    .take(range.len() - new_tokens.len());
 
+                // Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s, plus
+                // enough `FlatToken::Empty`s to fill up the rest of the range. This keeps the
+                // total length of `tokens` constant throughout the replacement process, allowing
+                // us to use all of the `ReplaceRanges` entries without adjusting indices.
+                let target_len = target.is_some() as usize;
                 tokens.splice(
                     (range.start as usize)..(range.end as usize),
-                    new_tokens.into_iter().chain(filler),
+                    target
+                        .into_iter()
+                        .map(|target| (FlatToken::AttrsTarget(target), Spacing::Alone))
+                        .chain(
+                            iter::repeat((FlatToken::Empty, Spacing::Alone))
+                                .take(range.len() - target_len),
+                        ),
                 );
             }
-            make_token_stream(tokens.into_iter(), self.break_last_token)
-        } else {
-            make_token_stream(tokens, self.break_last_token)
+            make_attr_token_stream(tokens.into_iter(), self.break_last_token)
         }
     }
 }
@@ -218,24 +215,23 @@ impl<'a> Parser<'a> {
         let start_token = (self.token.clone(), self.token_spacing);
         let cursor_snapshot = self.token_cursor.clone();
         let start_pos = self.num_bump_calls;
-
         let has_outer_attrs = !attrs.attrs.is_empty();
-        let prev_capturing = std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes);
         let replace_ranges_start = self.capture_state.replace_ranges.len();
 
-        let ret = f(self, attrs.attrs);
-
-        self.capture_state.capturing = prev_capturing;
-
-        let (mut ret, trailing) = ret?;
+        let (mut ret, trailing) = {
+            let prev_capturing = mem::replace(&mut self.capture_state.capturing, Capturing::Yes);
+            let ret_and_trailing = f(self, attrs.attrs);
+            self.capture_state.capturing = prev_capturing;
+            ret_and_trailing?
+        };
 
         // When we're not in `capture-cfg` mode, then bail out early if:
         // 1. Our target doesn't support tokens at all (e.g we're parsing an `NtIdent`)
         //    so there's nothing for us to do.
         // 2. Our target already has tokens set (e.g. we've parsed something
-        // like `#[my_attr] $item`. The actual parsing code takes care of prepending
-        // any attributes to the nonterminal, so we don't need to modify the
-        // already captured tokens.
+        //    like `#[my_attr] $item`). The actual parsing code takes care of
+        //    prepending any attributes to the nonterminal, so we don't need to
+        //    modify the already captured tokens.
         // Note that this check is independent of `force_collect`- if we already
         // have tokens, or can't even store them, then there's never a need to
         // force collection of new tokens.
@@ -276,37 +272,32 @@ impl<'a> Parser<'a> {
 
         let replace_ranges_end = self.capture_state.replace_ranges.len();
 
-        let mut end_pos = self.num_bump_calls;
-
-        let mut captured_trailing = false;
-
         // Capture a trailing token if requested by the callback 'f'
-        match trailing {
-            TrailingToken::None => {}
+        let captured_trailing = match trailing {
+            TrailingToken::None => false,
             TrailingToken::Gt => {
                 assert_eq!(self.token.kind, token::Gt);
+                false
             }
             TrailingToken::Semi => {
                 assert_eq!(self.token.kind, token::Semi);
-                end_pos += 1;
-                captured_trailing = true;
+                true
             }
-            TrailingToken::MaybeComma => {
-                if self.token.kind == token::Comma {
-                    end_pos += 1;
-                    captured_trailing = true;
-                }
-            }
-        }
+            TrailingToken::MaybeComma => self.token.kind == token::Comma,
+        };
 
-        // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens),
-        // then extend the range of captured tokens to include it, since the parser
-        // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted
-        // into an `AttrTokenStream`, we will create the proper token.
-        if self.break_last_token {
-            assert!(!captured_trailing, "Cannot set break_last_token and have trailing token");
-            end_pos += 1;
-        }
+        assert!(
+            !(self.break_last_token && captured_trailing),
+            "Cannot set break_last_token and have trailing token"
+        );
+
+        let end_pos = self.num_bump_calls
+            + captured_trailing as u32
+            // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), then
+            // extend the range of captured tokens to include it, since the parser was not actually
+            // bumped past it. When the `LazyAttrTokenStream` gets converted into an
+            // `AttrTokenStream`, we will create the proper token.
+            + self.break_last_token as u32;
 
         let num_calls = end_pos - start_pos;
 
@@ -318,14 +309,11 @@ impl<'a> Parser<'a> {
             // Grab any replace ranges that occur *inside* the current AST node.
             // We will perform the actual replacement when we convert the `LazyAttrTokenStream`
             // to an `AttrTokenStream`.
-            let start_calls: u32 = start_pos.try_into().unwrap();
             self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
                 .iter()
                 .cloned()
                 .chain(inner_attr_replace_ranges.iter().cloned())
-                .map(|(range, tokens)| {
-                    ((range.start - start_calls)..(range.end - start_calls), tokens)
-                })
+                .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data))
                 .collect()
         };
 
@@ -340,7 +328,7 @@ impl<'a> Parser<'a> {
         // If we support tokens at all
         if let Some(target_tokens) = ret.tokens_mut() {
             if target_tokens.is_none() {
-                // Store se our newly captured tokens into the AST node
+                // Store our newly captured tokens into the AST node.
                 *target_tokens = Some(tokens.clone());
             }
         }
@@ -355,18 +343,14 @@ impl<'a> Parser<'a> {
             && matches!(self.capture_state.capturing, Capturing::Yes)
             && has_cfg_or_cfg_attr(final_attrs)
         {
-            let attr_data = AttributesData { attrs: final_attrs.iter().cloned().collect(), tokens };
+            assert!(!self.break_last_token, "Should not have unglued last token with cfg attr");
 
-            // Replace the entire AST node that we just parsed, including attributes,
-            // with a `FlatToken::AttrTarget`. If this AST node is inside an item
-            // that has `#[derive]`, then this will allow us to cfg-expand this
-            // AST node.
+            // Replace the entire AST node that we just parsed, including attributes, with
+            // `target`. If this AST node is inside an item that has `#[derive]`, then this will
+            // allow us to cfg-expand this AST node.
             let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos };
-            let new_tokens = vec![(FlatToken::AttrTarget(attr_data), Spacing::Alone)];
-
-            assert!(!self.break_last_token, "Should not have unglued last token with cfg attr");
-            let range: Range<u32> = (start_pos.try_into().unwrap())..(end_pos.try_into().unwrap());
-            self.capture_state.replace_ranges.push((range, new_tokens));
+            let target = AttrsTarget { attrs: final_attrs.iter().cloned().collect(), tokens };
+            self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target)));
             self.capture_state.replace_ranges.extend(inner_attr_replace_ranges);
         }
 
@@ -382,10 +366,10 @@ impl<'a> Parser<'a> {
     }
 }
 
-/// Converts a flattened iterator of tokens (including open and close delimiter tokens)
-/// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair
-/// of open and close delims.
-fn make_token_stream(
+/// Converts a flattened iterator of tokens (including open and close delimiter tokens) into an
+/// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and
+/// close delims.
+fn make_attr_token_stream(
     mut iter: impl Iterator<Item = (FlatToken, Spacing)>,
     break_last_token: bool,
 ) -> AttrTokenStream {
@@ -428,11 +412,11 @@ fn make_token_stream(
                 .expect("Bottom token frame is missing!")
                 .inner
                 .push(AttrTokenTree::Token(token, spacing)),
-            FlatToken::AttrTarget(data) => stack
+            FlatToken::AttrsTarget(target) => stack
                 .last_mut()
                 .expect("Bottom token frame is missing!")
                 .inner
-                .push(AttrTokenTree::Attributes(data)),
+                .push(AttrTokenTree::AttrsTarget(target)),
             FlatToken::Empty => {}
         }
         token_and_spacing = iter.next();
@@ -464,6 +448,6 @@ mod size_asserts {
     use rustc_data_structures::static_assert_size;
     // tidy-alphabetical-start
     static_assert_size!(AttrWrapper, 16);
-    static_assert_size!(LazyAttrTokenStreamImpl, 104);
+    static_assert_size!(LazyAttrTokenStreamImpl, 96);
     // tidy-alphabetical-end
 }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index cfd0a72c056..45ca267fe5d 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -20,7 +20,7 @@ use path::PathStyle;
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
+use rustc_ast::tokenstream::{AttrsTarget, DelimSpacing, DelimSpan, Spacing};
 use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
 use rustc_ast::util::case::Case;
 use rustc_ast::{
@@ -153,7 +153,7 @@ pub struct Parser<'a> {
     expected_tokens: Vec<TokenType>,
     token_cursor: TokenCursor,
     // The number of calls to `bump`, i.e. the position in the token stream.
-    num_bump_calls: usize,
+    num_bump_calls: u32,
     // During parsing we may sometimes need to 'unglue' a glued token into two
     // component tokens (e.g. '>>' into '>' and '>), so the parser can consume
     // them one at a time. This process bypasses the normal capturing mechanism
@@ -192,7 +192,7 @@ pub struct Parser<'a> {
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
 // it doesn't unintentionally get bigger.
 #[cfg(target_pointer_width = "64")]
-rustc_data_structures::static_assert_size!(Parser<'_>, 264);
+rustc_data_structures::static_assert_size!(Parser<'_>, 256);
 
 /// Stores span information about a closure.
 #[derive(Clone, Debug)]
@@ -203,13 +203,13 @@ struct ClosureSpans {
 }
 
 /// Indicates a range of tokens that should be replaced by
-/// the tokens in the provided vector. This is used in two
+/// the tokens in the provided `AttrsTarget`. This is used in two
 /// places during token collection:
 ///
 /// 1. During the parsing of an AST node that may have a `#[derive]`
 /// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]`
 /// In this case, we use a `ReplaceRange` to replace the entire inner AST node
-/// with `FlatToken::AttrTarget`, allowing us to perform eager cfg-expansion
+/// with `FlatToken::AttrsTarget`, allowing us to perform eager cfg-expansion
 /// on an `AttrTokenStream`.
 ///
 /// 2. When we parse an inner attribute while collecting tokens. We
@@ -219,7 +219,7 @@ struct ClosureSpans {
 /// the first macro inner attribute to invoke a proc-macro).
 /// When create a `TokenStream`, the inner attributes get inserted
 /// into the proper place in the token stream.
-type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>);
+type ReplaceRange = (Range<u32>, Option<AttrsTarget>);
 
 /// Controls how we capture tokens. Capturing can be expensive,
 /// so we try to avoid performing capturing in cases where
@@ -1572,7 +1572,7 @@ impl<'a> Parser<'a> {
         self.expected_tokens.clear();
     }
 
-    pub fn approx_token_stream_pos(&self) -> usize {
+    pub fn approx_token_stream_pos(&self) -> u32 {
         self.num_bump_calls
     }
 }
@@ -1608,11 +1608,10 @@ enum FlatToken {
     /// A token - this holds both delimiter (e.g. '{' and '}')
     /// and non-delimiter tokens
     Token(Token),
-    /// Holds the `AttributesData` for an AST node. The
-    /// `AttributesData` is inserted directly into the
-    /// constructed `AttrTokenStream` as
-    /// an `AttrTokenTree::Attributes`.
-    AttrTarget(AttributesData),
+    /// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted
+    /// directly into the constructed `AttrTokenStream` as an
+    /// `AttrTokenTree::AttrsTarget`.
+    AttrsTarget(AttrsTarget),
     /// A special 'empty' token that is ignored during the conversion
     /// to an `AttrTokenStream`. This is used to simplify the
     /// handling of replace ranges.
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index da8d1194325..03c647dd527 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -353,18 +353,17 @@ impl<'a> Parser<'a> {
                     })?;
                     let span = lo.to(self.prev_token.span);
                     AngleBracketedArgs { args, span }.into()
-                } else if self.may_recover()
-                    && self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
+                } else if self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
                     // FIXME(return_type_notation): Could also recover `...` here.
                     && self.look_ahead(1, |tok| tok.kind == token::DotDot)
                 {
-                    self.bump();
-                    self.dcx()
-                        .emit_err(errors::BadReturnTypeNotationDotDot { span: self.token.span });
-                    self.bump();
+                    self.bump(); // (
+                    self.bump(); // ..
                     self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
                     let span = lo.to(self.prev_token.span);
 
+                    self.psess.gated_spans.gate(sym::return_type_notation, span);
+
                     if self.eat_noexpect(&token::RArrow) {
                         let lo = self.prev_token.span;
                         let ty = self.parse_ty()?;
@@ -372,13 +371,7 @@ impl<'a> Parser<'a> {
                             .emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) });
                     }
 
-                    ParenthesizedArgs {
-                        span,
-                        inputs: ThinVec::new(),
-                        inputs_span: span,
-                        output: ast::FnRetTy::Default(self.prev_token.span.shrink_to_hi()),
-                    }
-                    .into()
+                    P(ast::GenericArgs::ParenthesizedElided(span))
                 } else {
                     // `(T, U) -> R`
 
@@ -733,14 +726,6 @@ impl<'a> Parser<'a> {
 
                     let span = lo.to(self.prev_token.span);
 
-                    if let AssocItemConstraintKind::Bound { .. } = kind
-                        && let Some(ast::GenericArgs::Parenthesized(args)) = &gen_args
-                        && args.inputs.is_empty()
-                        && let ast::FnRetTy::Default(..) = args.output
-                    {
-                        self.psess.gated_spans.gate(sym::return_type_notation, span);
-                    }
-
                     let constraint =
                         AssocItemConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
                     Ok(Some(AngleBracketedArg::Constraint(constraint)))
diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs
index 0c3dd649997..839b96fb3de 100644
--- a/compiler/rustc_passes/src/abi_test.rs
+++ b/compiler/rustc_passes/src/abi_test.rs
@@ -61,7 +61,7 @@ fn unwrap_fn_abi<'tcx>(
 fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
     let param_env = tcx.param_env(item_def_id);
     let args = GenericArgs::identity_for_item(tcx, item_def_id);
-    let instance = match Instance::resolve(tcx, param_env, item_def_id.into(), args) {
+    let instance = match Instance::try_resolve(tcx, param_env, item_def_id.into(), args) {
         Ok(Some(instance)) => instance,
         Ok(None) => {
             // Not sure what to do here, but `LayoutError::Unknown` seems reasonable?
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 0eb9d1ce59f..ce2fa83810f 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -34,8 +34,8 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{BytePos, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 use std::cell::Cell;
 use std::collections::hash_map::Entry;
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index bbd586386dd..55514883cb1 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -102,7 +102,7 @@ fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness {
     Publicness::new(true, true)
 }
 
-/// Determine if a work from the worklist is coming from the a `#[allow]`
+/// Determine if a work from the worklist is coming from a `#[allow]`
 /// or a `#[expect]` of `dead_code`
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 enum ComesFromAllowExpect {
@@ -277,7 +277,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         pats: &[hir::PatField<'_>],
     ) {
         let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
-            ty::Adt(adt, _) => adt.variant_of_res(res),
+            ty::Adt(adt, _) => {
+                self.check_def_id(adt.did());
+                adt.variant_of_res(res)
+            }
             _ => span_bug!(lhs.span, "non-ADT in struct pattern"),
         };
         for pat in pats {
@@ -297,7 +300,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         dotdot: hir::DotDotPos,
     ) {
         let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
-            ty::Adt(adt, _) => adt.variant_of_res(res),
+            ty::Adt(adt, _) => {
+                self.check_def_id(adt.did());
+                adt.variant_of_res(res)
+            }
             _ => {
                 self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern");
                 return;
@@ -402,31 +408,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 return false;
             }
 
-            // don't ignore impls for Enums and pub Structs whose methods don't have self receiver,
-            // cause external crate may call such methods to construct values of these types
-            if let Some(local_impl_of) = impl_of.as_local()
-                && let Some(local_def_id) = def_id.as_local()
-                && let Some(fn_sig) =
-                    self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
-                && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
-                && let TyKind::Path(hir::QPath::Resolved(_, path)) =
-                    self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind
-                && let Res::Def(def_kind, did) = path.res
-            {
-                match def_kind {
-                    // for example, #[derive(Default)] pub struct T(i32);
-                    // external crate can call T::default() to construct T,
-                    // so that don't ignore impl Default for pub Enum and Structs
-                    DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => {
-                        return false;
-                    }
-                    // don't ignore impl Default for Enums,
-                    // cause we don't know which variant is constructed
-                    DefKind::Enum => return false,
-                    _ => (),
-                };
-            }
-
             if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
                 && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
             {
@@ -690,6 +671,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
                 self.handle_field_pattern_match(pat, res, fields);
             }
             PatKind::Path(ref qpath) => {
+                if let ty::Adt(adt, _) = self.typeck_results().node_type(pat.hir_id).kind() {
+                    self.check_def_id(adt.did());
+                }
                 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
                 self.handle_res(res);
             }
@@ -845,7 +829,7 @@ fn check_item<'tcx>(
                 // mark the method live if the self_ty is public,
                 // or the method is public and may construct self
                 if tcx.visibility(local_def_id).is_public()
-                    && (ty_and_all_fields_are_public || may_construct_self)
+                    && (ty_and_all_fields_are_public || (ty_is_public && may_construct_self))
                 {
                     // if the impl item is public,
                     // and the ty may be constructed or can be constructed in foreign crates,
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 0ba61f8e8b4..0720efebf97 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -695,7 +695,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
     fn visit_generic_args(&mut self, g: &'v ast::GenericArgs) {
         record_variants!(
             (self, g, g, Id::None, ast, GenericArgs, GenericArgs),
-            [AngleBracketed, Parenthesized]
+            [AngleBracketed, Parenthesized, ParenthesizedElided]
         );
         ast_visit::walk_generic_args(self, g)
     }
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index c9a47650456..603e98cfa92 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -8,7 +8,7 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, TargetDataLayout};
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
 use rustc_trait_selection::{infer::TyCtxtInferExt, traits};
 
 use crate::errors::{
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 6dd8eaf7e67..dee8ba7e87d 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -310,7 +310,7 @@ impl<'tcx> ReachableContext<'tcx> {
                 GlobalAlloc::Static(def_id) => {
                     self.propagate_item(Res::Def(self.tcx.def_kind(def_id), def_id))
                 }
-                GlobalAlloc::Function(instance) => {
+                GlobalAlloc::Function { instance, .. } => {
                     // Manually visit to actually see the instance's `DefId`. Type visitors won't see it
                     self.propagate_item(Res::Def(
                         self.tcx.def_kind(instance.def_id()),
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index b6ae54010c2..b71853b871d 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-pulldown-cmark = { version = "0.9.6", default-features = false }
+pulldown-cmark = { version = "0.11", features = ["html"], default-features = false }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 4e0f2792d97..92cf73870ff 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -321,8 +321,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             // The fields are not expanded yet.
             return;
         }
-        let def_ids = fields.iter().map(|field| self.r.local_def_id(field.id).to_def_id());
-        self.r.field_def_ids.insert(def_id, self.r.tcx.arena.alloc_from_iter(def_ids));
+        let fields = fields
+            .iter()
+            .enumerate()
+            .map(|(i, field)| {
+                field.ident.unwrap_or_else(|| Ident::from_str_and_span(&format!("{i}"), field.span))
+            })
+            .collect();
+        self.r.field_names.insert(def_id, fields);
     }
 
     fn insert_field_visibilities_local(&mut self, def_id: DefId, fields: &[ast::FieldDef]) {
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 80619c59cc3..a4fdb4a0baf 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -8,6 +8,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_span::hygiene::LocalExpnId;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
+use std::mem;
 use tracing::debug;
 
 pub(crate) fn collect_definitions(
@@ -15,8 +16,9 @@ pub(crate) fn collect_definitions(
     fragment: &AstFragment,
     expansion: LocalExpnId,
 ) {
-    let (parent_def, impl_trait_context) = resolver.invocation_parents[&expansion];
-    fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion, impl_trait_context });
+    let (parent_def, impl_trait_context, in_attr) = resolver.invocation_parents[&expansion];
+    let mut visitor = DefCollector { resolver, parent_def, expansion, impl_trait_context, in_attr };
+    fragment.visit_with(&mut visitor);
 }
 
 /// Creates `DefId`s for nodes in the AST.
@@ -24,6 +26,7 @@ struct DefCollector<'a, 'b, 'tcx> {
     resolver: &'a mut Resolver<'b, 'tcx>,
     parent_def: LocalDefId,
     impl_trait_context: ImplTraitContext,
+    in_attr: bool,
     expansion: LocalExpnId,
 }
 
@@ -53,7 +56,7 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
     }
 
     fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
-        let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def);
+        let orig_parent_def = mem::replace(&mut self.parent_def, parent_def);
         f(self);
         self.parent_def = orig_parent_def;
     }
@@ -63,7 +66,7 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
         impl_trait_context: ImplTraitContext,
         f: F,
     ) {
-        let orig_itc = std::mem::replace(&mut self.impl_trait_context, impl_trait_context);
+        let orig_itc = mem::replace(&mut self.impl_trait_context, impl_trait_context);
         f(self);
         self.impl_trait_context = orig_itc;
     }
@@ -105,8 +108,10 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
 
     fn visit_macro_invoc(&mut self, id: NodeId) {
         let id = id.placeholder_to_expn_id();
-        let old_parent =
-            self.resolver.invocation_parents.insert(id, (self.parent_def, self.impl_trait_context));
+        let old_parent = self
+            .resolver
+            .invocation_parents
+            .insert(id, (self.parent_def, self.impl_trait_context, self.in_attr));
         assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
     }
 }
@@ -413,4 +418,10 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
             visit::walk_crate(self, krate)
         }
     }
+
+    fn visit_attribute(&mut self, attr: &'a Attribute) -> Self::Result {
+        let orig_in_attr = mem::replace(&mut self.in_attr, true);
+        visit::walk_attribute(self, attr);
+        self.in_attr = orig_in_attr;
+    }
 }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 263daa11ec3..ffd495aa985 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1726,11 +1726,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         )) = binding.kind
         {
             let def_id = self.tcx.parent(ctor_def_id);
-            return self
-                .field_def_ids(def_id)?
-                .iter()
-                .map(|&field_id| self.def_span(field_id))
-                .reduce(Span::to); // None for `struct Foo()`
+            return self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to); // None for `struct Foo()`
         }
         None
     }
@@ -1987,10 +1983,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             candidates
                 .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path)));
             if let Some(candidate) = candidates.get(0) {
+                let path = {
+                    // remove the possible common prefix of the path
+                    let start_index = (0..failed_segment_idx)
+                        .find(|&i| path[i].ident != candidate.path.segments[i].ident)
+                        .unwrap_or_default();
+                    let segments = (start_index..=failed_segment_idx)
+                        .map(|s| candidate.path.segments[s].clone())
+                        .collect();
+                    Path { segments, span: Span::default(), tokens: None }
+                };
                 (
                     String::from("unresolved import"),
                     Some((
-                        vec![(ident.span, pprust::path_to_string(&candidate.path))],
+                        vec![(ident.span, pprust::path_to_string(&path))],
                         String::from("a similar path exists"),
                         Applicability::MaybeIncorrect,
                     )),
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 66a1c05289b..1d37264f96a 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1221,6 +1221,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                         }
                     }
                 }
+                GenericArgs::ParenthesizedElided(_) => {}
             }
         }
     }
@@ -1743,7 +1744,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                             ) {
                                 self.r.dcx().emit_err(errors::LendingIteratorReportError {
                                     lifetime: lifetime.ident.span,
-                                    ty: ty.span(),
+                                    ty: ty.span,
                                 });
                             } else {
                                 self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 764cc350182..941fb6436df 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1532,17 +1532,17 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     if !this.has_private_fields(def_id) {
                         // If the fields of the type are private, we shouldn't be suggesting using
                         // the struct literal syntax at all, as that will cause a subsequent error.
-                        let field_ids = this.r.field_def_ids(def_id);
-                        let (fields, applicability) = match field_ids {
-                            Some(field_ids) => {
-                                let fields = field_ids.iter().map(|&id| this.r.tcx.item_name(id));
-
+                        let fields = this.r.field_idents(def_id);
+                        let has_fields = fields.as_ref().is_some_and(|f| !f.is_empty());
+                        let (fields, applicability) = match fields {
+                            Some(fields) => {
                                 let fields = if let Some(old_fields) = old_fields {
                                     fields
+                                        .iter()
                                         .enumerate()
                                         .map(|(idx, new)| (new, old_fields.get(idx)))
                                         .map(|(new, old)| {
-                                            let new = new.to_ident_string();
+                                            let new = new.name.to_ident_string();
                                             if let Some(Some(old)) = old
                                                 && new != *old
                                             {
@@ -1553,17 +1553,17 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                                         })
                                         .collect::<Vec<String>>()
                                 } else {
-                                    fields.map(|f| format!("{f}{tail}")).collect::<Vec<String>>()
+                                    fields
+                                        .iter()
+                                        .map(|f| format!("{f}{tail}"))
+                                        .collect::<Vec<String>>()
                                 };
 
                                 (fields.join(", "), applicability)
                             }
                             None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
                         };
-                        let pad = match field_ids {
-                            Some([]) => "",
-                            _ => " ",
-                        };
+                        let pad = if has_fields { " " } else { "" };
                         err.span_suggestion(
                             span,
                             format!("use struct {descr} syntax instead"),
@@ -1723,12 +1723,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                             &args[..],
                         );
                         // Use spans of the tuple struct definition.
-                        self.r.field_def_ids(def_id).map(|field_ids| {
-                            field_ids
-                                .iter()
-                                .map(|&field_id| self.r.def_span(field_id))
-                                .collect::<Vec<_>>()
-                        })
+                        self.r
+                            .field_idents(def_id)
+                            .map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
                     }
                     _ => None,
                 };
@@ -1791,7 +1788,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             (Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_def_id), _) if ns == ValueNS => {
                 let def_id = self.r.tcx.parent(ctor_def_id);
                 err.span_label(self.r.def_span(def_id), format!("`{path_str}` defined here"));
-                let fields = self.r.field_def_ids(def_id).map_or_else(
+                let fields = self.r.field_idents(def_id).map_or_else(
                     || "/* fields */".to_string(),
                     |field_ids| vec!["_"; field_ids.len()].join(", "),
                 );
@@ -2017,12 +2014,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) =
                         resolution.full_res()
                     {
-                        if let Some(field_ids) = self.r.field_def_ids(did) {
-                            if let Some(field_id) = field_ids
-                                .iter()
-                                .find(|&&field_id| ident.name == self.r.tcx.item_name(field_id))
-                            {
-                                return Some(AssocSuggestion::Field(self.r.def_span(*field_id)));
+                        if let Some(fields) = self.r.field_idents(did) {
+                            if let Some(field) = fields.iter().find(|id| ident.name == id.name) {
+                                return Some(AssocSuggestion::Field(field.span));
                             }
                         }
                     }
@@ -2418,7 +2412,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 match kind {
                     CtorKind::Const => false,
                     CtorKind::Fn => {
-                        !self.r.field_def_ids(def_id).is_some_and(|field_ids| field_ids.is_empty())
+                        !self.r.field_idents(def_id).is_some_and(|field_ids| field_ids.is_empty())
                     }
                 }
             };
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 94cdce1025f..7cb5a3fb2fd 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -350,6 +350,7 @@ impl<'a> From<&'a ast::PathSegment> for Segment {
                     (args.span, found_lifetimes)
                 }
                 GenericArgs::Parenthesized(args) => (args.span, true),
+                GenericArgs::ParenthesizedElided(span) => (*span, true),
             }
         } else {
             (DUMMY_SP, false)
@@ -990,7 +991,7 @@ pub struct Resolver<'a, 'tcx> {
     extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'a>>,
 
     /// N.B., this is used only for better diagnostics, not name resolution itself.
-    field_def_ids: LocalDefIdMap<&'tcx [DefId]>,
+    field_names: LocalDefIdMap<Vec<Ident>>,
 
     /// Span of the privacy modifier in fields of an item `DefId` accessible with dot syntax.
     /// Used for hints during error reporting.
@@ -1138,7 +1139,7 @@ pub struct Resolver<'a, 'tcx> {
     /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
     /// we know what parent node that fragment should be attached to thanks to this table,
     /// and how the `impl Trait` fragments were introduced.
-    invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext)>,
+    invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext, bool /*in_attr*/)>,
 
     /// Some way to know that we are in a *trait* impl in `visit_assoc_item`.
     /// FIXME: Replace with a more general AST map (together with some other fields).
@@ -1370,7 +1371,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         node_id_to_def_id.insert(CRATE_NODE_ID, crate_feed);
 
         let mut invocation_parents = FxHashMap::default();
-        invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential));
+        invocation_parents
+            .insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential, false));
 
         let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = tcx
             .sess
@@ -1405,7 +1407,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             prelude: None,
             extern_prelude,
 
-            field_def_ids: Default::default(),
+            field_names: Default::default(),
             field_visibility_spans: FxHashMap::default(),
 
             determined_imports: Vec::new(),
@@ -2126,10 +2128,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
     }
 
-    fn field_def_ids(&self, def_id: DefId) -> Option<&'tcx [DefId]> {
+    fn field_idents(&self, def_id: DefId) -> Option<Vec<Ident>> {
         match def_id.as_local() {
-            Some(def_id) => self.field_def_ids.get(&def_id).copied(),
-            None => Some(self.tcx.associated_item_def_ids(def_id)),
+            Some(def_id) => self.field_names.get(&def_id).cloned(),
+            None => Some(
+                self.tcx
+                    .associated_item_def_ids(def_id)
+                    .iter()
+                    .map(|&def_id| {
+                        Ident::new(self.tcx.item_name(def_id), self.tcx.def_span(def_id))
+                    })
+                    .collect(),
+            ),
         }
     }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 026a2ca1412..cb9bebd33d3 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -297,11 +297,12 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
             .invocation_parents
             .get(&invoc_id)
             .or_else(|| self.invocation_parents.get(&eager_expansion_root))
-            .map(|&(mod_def_id, _)| mod_def_id)
-            .filter(|&mod_def_id| {
-                invoc.fragment_kind == AstFragmentKind::Expr
+            .filter(|&&(mod_def_id, _, in_attr)| {
+                in_attr
+                    && invoc.fragment_kind == AstFragmentKind::Expr
                     && self.tcx.def_kind(mod_def_id) == DefKind::Mod
-            });
+            })
+            .map(|&(mod_def_id, ..)| mod_def_id);
         let (ext, res) = self.smart_resolve_macro_path(
             path,
             kind,
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 66b4981eb55..59460815321 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -1,4 +1,6 @@
-use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag};
+use pulldown_cmark::{
+    BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, Options, Parser, Tag,
+};
 use rustc_ast as ast;
 use rustc_ast::util::comments::beautify_doc_string;
 use rustc_data_structures::fx::FxHashMap;
@@ -427,7 +429,9 @@ fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
 
     while let Some(event) = event_iter.next() {
         match event {
-            Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
+            Event::Start(Tag::Link { link_type, dest_url, title: _, id: _ })
+                if may_be_doc_link(link_type) =>
+            {
                 if matches!(
                     link_type,
                     LinkType::Inline
@@ -441,7 +445,7 @@ fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
                     }
                 }
 
-                links.push(preprocess_link(&dest));
+                links.push(preprocess_link(&dest_url));
             }
             _ => {}
         }
@@ -451,8 +455,8 @@ fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
 }
 
 /// Collects additional data of link.
-fn collect_link_data<'input, 'callback>(
-    event_iter: &mut Parser<'input, 'callback>,
+fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
+    event_iter: &mut Parser<'input, F>,
 ) -> Option<Box<str>> {
     let mut display_text: Option<String> = None;
     let mut append_text = |text: CowStr<'_>| {
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 1dcb69920d7..d27dfd88824 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -155,7 +155,7 @@ impl FileEncoder {
         if std::intrinsics::unlikely(self.buffered > flush_threshold) {
             self.flush();
         }
-        // SAFETY: We checked above that that N < self.buffer_empty().len(),
+        // SAFETY: We checked above that N < self.buffer_empty().len(),
         // and if isn't, flush ensures that our empty buffer is now BUF_SIZE.
         // We produce a post-mono error if N > BUF_SIZE.
         let buf = unsafe { self.buffer_empty().first_chunk_mut::<N>().unwrap_unchecked() };
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 80f7ca544f3..7421cae65e4 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1630,8 +1630,6 @@ options! {
         "only allow the listed language features to be enabled in code (comma separated)"),
     always_encode_mir: bool = (false, parse_bool, [TRACKED],
         "encode MIR of all functions into the crate metadata (default: no)"),
-    asm_comments: bool = (false, parse_bool, [TRACKED],
-        "generate comments into the assembly (may change behavior) (default: no)"),
     assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "assert that the incremental cache is in given state: \
          either `loaded` or `not-loaded`."),
@@ -1766,6 +1764,8 @@ options! {
         "enable LLVM inlining (default: yes)"),
     inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable MIR inlining (default: no)"),
+    inline_mir_forwarder_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
+        "inlining threshold when the caller is a simple forwarding function (default: 30)"),
     inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
         "inlining threshold for functions with inline hint (default: 100)"),
     inline_mir_preserve_debug: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -2105,6 +2105,8 @@ written to standard error output)"),
         "Generate sync unwind tables instead of async unwind tables (default: no)"),
     validate_mir: bool = (false, parse_bool, [UNTRACKED],
         "validate MIR after each transformation"),
+    verbose_asm: bool = (false, parse_bool, [TRACKED],
+        "add descriptive comments from LLVM to the assembly (may change behavior) (default: no)"),
     #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")]
     verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH],
         "in general, enable more debug printouts (default: no)"),
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 4eefd0eb17c..b0ced8e920f 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -629,7 +629,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         let def_id = def.0.internal(&mut *tables, tcx);
         let args_ref = args.internal(&mut *tables, tcx);
-        match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
+        match Instance::try_resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
             Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
             Ok(None) | Err(_) => None,
         }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index f15b82d0c03..8bfaa112c2f 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -644,6 +644,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
                 target: target.map(|t| t.as_usize()),
                 unwind: unwind.stable(tables),
             },
+            mir::TerminatorKind::TailCall { func: _, args: _, fn_span: _ } => todo!(),
             mir::TerminatorKind::Assert { cond, expected, msg, target, unwind } => {
                 TerminatorKind::Assert {
                     cond: cond.stable(tables),
@@ -709,7 +710,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> {
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
         match self {
-            mir::interpret::GlobalAlloc::Function(instance) => {
+            mir::interpret::GlobalAlloc::Function { instance, .. } => {
                 GlobalAlloc::Function(instance.stable(tables))
             }
             mir::interpret::GlobalAlloc::VTable(ty, trait_ref) => {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 7da9211bcbf..af56f4e5141 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1513,6 +1513,7 @@ symbols! {
         recursion_limit,
         reexport_test_harness_main,
         ref_pat_eat_one_layer_2024,
+        ref_pat_eat_one_layer_2024_structural,
         ref_pat_everywhere,
         ref_unwind_safe_trait,
         reference,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 9edd2ff9b1a..5aa46cc0dea 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -85,9 +85,13 @@ pub(super) fn mangle<'tcx>(
         }
         // FIXME(async_closures): This shouldn't be needed when we fix
         // `Instance::ty`/`Instance::def_id`.
-        ty::InstanceKind::ConstructCoroutineInClosureShim { .. }
-        | ty::InstanceKind::CoroutineKindShim { .. } => {
-            printer.write_str("{{fn-once-shim}}").unwrap();
+        ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref, .. } => {
+            printer
+                .write_str(if receiver_by_ref { "{{by-move-shim}}" } else { "{{by-ref-shim}}" })
+                .unwrap();
+        }
+        ty::InstanceKind::CoroutineKindShim { .. } => {
+            printer.write_str("{{by-move-body-shim}}").unwrap();
         }
         _ => {}
     }
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 42c4fa83d1b..5f8029af020 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -49,8 +49,15 @@ pub(super) fn mangle<'tcx>(
         ty::InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"),
         ty::InstanceKind::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"),
 
-        ty::InstanceKind::ConstructCoroutineInClosureShim { .. }
-        | ty::InstanceKind::CoroutineKindShim { .. } => Some("fn_once"),
+        // FIXME(async_closures): This shouldn't be needed when we fix
+        // `Instance::ty`/`Instance::def_id`.
+        ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref: true, .. } => {
+            Some("by_move")
+        }
+        ty::InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref: false, .. } => {
+            Some("by_ref")
+        }
+        ty::InstanceKind::CoroutineKindShim { .. } => Some("by_move_body"),
 
         _ => None,
     };
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 5713542c17d..8058130f441 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -339,7 +339,9 @@ impl CastTarget {
         }
     }
 
-    pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
+    /// When you only access the range containing valid data, you can use this unaligned size;
+    /// otherwise, use the safer `size` method.
+    pub fn unaligned_size<C: HasDataLayout>(&self, _cx: &C) -> Size {
         // Prefix arguments are passed in specific designated registers
         let prefix_size = self
             .prefix
@@ -353,6 +355,10 @@ impl CastTarget {
         prefix_size + rest_size
     }
 
+    pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
+        self.unaligned_size(cx).align_to(self.align(cx))
+    }
+
     pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
         self.prefix
             .iter()
diff --git a/compiler/rustc_trait_selection/src/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/mod.rs
new file mode 100644
index 00000000000..f6ac8fc7b61
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/error_reporting/mod.rs
@@ -0,0 +1 @@
+pub mod traits;
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
new file mode 100644
index 00000000000..c301deac616
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -0,0 +1,698 @@
+use std::ops::ControlFlow;
+
+use rustc_errors::{
+    struct_span_code_err, Applicability, Diag, MultiSpan, StashKey, E0283, E0284, E0790,
+};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor as _;
+use rustc_hir::LangItem;
+use rustc_infer::infer::error_reporting::{TypeAnnotationNeeded, TypeErrCtxt};
+use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt};
+use rustc_infer::traits::util::elaborate;
+use rustc_infer::traits::{
+    Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation,
+};
+use rustc_macros::extension;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _};
+use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
+
+use crate::error_reporting::traits::suggestions::TypeErrCtxtExt as _;
+use crate::error_reporting::traits::{
+    to_pretty_impl_header, FindExprBySpan, InferCtxtPrivExt as _,
+};
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::ObligationCtxt;
+
+#[derive(Debug)]
+pub enum CandidateSource {
+    DefId(DefId),
+    ParamEnv(Span),
+}
+
+pub fn compute_applicable_impls_for_diagnostics<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    obligation: &PolyTraitObligation<'tcx>,
+) -> Vec<CandidateSource> {
+    let tcx = infcx.tcx;
+    let param_env = obligation.param_env;
+
+    let predicate_polarity = obligation.predicate.skip_binder().polarity;
+
+    let impl_may_apply = |impl_def_id| {
+        let ocx = ObligationCtxt::new(infcx);
+        infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
+            let obligation_trait_ref = ocx.normalize(
+                &ObligationCause::dummy(),
+                param_env,
+                placeholder_obligation.trait_ref,
+            );
+
+            let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
+            let impl_trait_ref =
+                tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args);
+            let impl_trait_ref =
+                ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
+
+            if let Err(_) =
+                ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
+            {
+                return false;
+            }
+
+            let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
+            let impl_polarity = impl_trait_header.polarity;
+
+            match (impl_polarity, predicate_polarity) {
+                (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
+                | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => {}
+                _ => return false,
+            }
+
+            let obligations = tcx
+                .predicates_of(impl_def_id)
+                .instantiate(tcx, impl_args)
+                .into_iter()
+                .map(|(predicate, _)| {
+                    Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
+                })
+                // Kinda hacky, but let's just throw away obligations that overflow.
+                // This may reduce the accuracy of this check (if the obligation guides
+                // inference or it actually resulted in error after others are processed)
+                // ... but this is diagnostics code.
+                .filter(|obligation| {
+                    infcx.next_trait_solver() || infcx.evaluate_obligation(obligation).is_ok()
+                });
+            ocx.register_obligations(obligations);
+
+            ocx.select_where_possible().is_empty()
+        })
+    };
+
+    let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
+        let ocx = ObligationCtxt::new(infcx);
+        infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
+            let obligation_trait_ref = ocx.normalize(
+                &ObligationCause::dummy(),
+                param_env,
+                placeholder_obligation.trait_ref,
+            );
+
+            let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
+                DUMMY_SP,
+                BoundRegionConversionTime::HigherRankedType,
+                poly_trait_predicate,
+            );
+            let param_env_trait_ref =
+                ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
+
+            if let Err(_) = ocx.eq(
+                &ObligationCause::dummy(),
+                param_env,
+                obligation_trait_ref,
+                param_env_trait_ref,
+            ) {
+                return false;
+            }
+
+            ocx.select_where_possible().is_empty()
+        })
+    };
+
+    let mut ambiguities = Vec::new();
+
+    tcx.for_each_relevant_impl(
+        obligation.predicate.def_id(),
+        obligation.predicate.skip_binder().trait_ref.self_ty(),
+        |impl_def_id| {
+            if infcx.probe(|_| impl_may_apply(impl_def_id)) {
+                ambiguities.push(CandidateSource::DefId(impl_def_id))
+            }
+        },
+    );
+
+    let predicates =
+        tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
+    for (pred, span) in elaborate(tcx, predicates.into_iter()) {
+        let kind = pred.kind();
+        if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
+            && param_env_candidate_may_apply(kind.rebind(trait_pred))
+        {
+            if kind.rebind(trait_pred.trait_ref)
+                == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id()))
+            {
+                ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id())))
+            } else {
+                ambiguities.push(CandidateSource::ParamEnv(span))
+            }
+        }
+    }
+
+    ambiguities
+}
+
+#[extension(pub trait TypeErrCtxtAmbiguityExt<'a, 'tcx>)]
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    #[instrument(skip(self), level = "debug")]
+    fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed {
+        // Unable to successfully determine, probably means
+        // insufficient type information, but could mean
+        // ambiguous impls. The latter *ought* to be a
+        // coherence violation, so we don't report it here.
+
+        let predicate = self.resolve_vars_if_possible(obligation.predicate);
+        let span = obligation.cause.span;
+
+        debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
+
+        // Ambiguity errors are often caused as fallout from earlier errors.
+        // We ignore them if this `infcx` is tainted in some cases below.
+
+        let bound_predicate = predicate.kind();
+        let mut err = match bound_predicate.skip_binder() {
+            ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
+                let trait_ref = bound_predicate.rebind(data.trait_ref);
+                debug!(?trait_ref);
+
+                if let Err(e) = predicate.error_reported() {
+                    return e;
+                }
+
+                if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) {
+                    // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
+                    // other `Foo` impls are incoherent.
+                    return guar;
+                }
+
+                // This is kind of a hack: it frequently happens that some earlier
+                // error prevents types from being fully inferred, and then we get
+                // a bunch of uninteresting errors saying something like "<generic
+                // #0> doesn't implement Sized". It may even be true that we
+                // could just skip over all checks where the self-ty is an
+                // inference variable, but I was afraid that there might be an
+                // inference variable created, registered as an obligation, and
+                // then never forced by writeback, and hence by skipping here we'd
+                // be ignoring the fact that we don't KNOW the type works
+                // out. Though even that would probably be harmless, given that
+                // we're only talking about builtin traits, which are known to be
+                // inhabited. We used to check for `self.tcx.sess.has_errors()` to
+                // avoid inundating the user with unnecessary errors, but we now
+                // check upstream for type errors and don't add the obligations to
+                // begin with in those cases.
+                if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
+                    match self.tainted_by_errors() {
+                        None => {
+                            let err = self.emit_inference_failure_err(
+                                obligation.cause.body_id,
+                                span,
+                                trait_ref.self_ty().skip_binder().into(),
+                                TypeAnnotationNeeded::E0282,
+                                false,
+                            );
+                            return err.stash(span, StashKey::MaybeForgetReturn).unwrap();
+                        }
+                        Some(e) => return e,
+                    }
+                }
+
+                // Typically, this ambiguity should only happen if
+                // there are unresolved type inference variables
+                // (otherwise it would suggest a coherence
+                // failure). But given #21974 that is not necessarily
+                // the case -- we can have multiple where clauses that
+                // are only distinguished by a region, which results
+                // in an ambiguity even when all types are fully
+                // known, since we don't dispatch based on region
+                // relationships.
+
+                // Pick the first generic parameter that still contains inference variables as the one
+                // we're going to emit an error for. If there are none (see above), fall back to
+                // a more general error.
+                let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer());
+
+                let mut err = if let Some(arg) = arg {
+                    self.emit_inference_failure_err(
+                        obligation.cause.body_id,
+                        span,
+                        arg,
+                        TypeAnnotationNeeded::E0283,
+                        true,
+                    )
+                } else {
+                    struct_span_code_err!(
+                        self.dcx(),
+                        span,
+                        E0283,
+                        "type annotations needed: cannot satisfy `{}`",
+                        predicate,
+                    )
+                };
+
+                let mut ambiguities = compute_applicable_impls_for_diagnostics(
+                    self.infcx,
+                    &obligation.with(self.tcx, trait_ref),
+                );
+                let has_non_region_infer =
+                    trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
+                // It doesn't make sense to talk about applicable impls if there are more than a
+                // handful of them. If there are a lot of them, but only a few of them have no type
+                // params, we only show those, as they are more likely to be useful/intended.
+                if ambiguities.len() > 5 {
+                    let infcx = self.infcx;
+                    if !ambiguities.iter().all(|option| match option {
+                        CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
+                        CandidateSource::ParamEnv(_) => true,
+                    }) {
+                        // If not all are blanket impls, we filter blanked impls out.
+                        ambiguities.retain(|option| match option {
+                            CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
+                            CandidateSource::ParamEnv(_) => true,
+                        });
+                    }
+                }
+                if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
+                    if let Some(e) = self.tainted_by_errors()
+                        && arg.is_none()
+                    {
+                        // If `arg.is_none()`, then this is probably two param-env
+                        // candidates or impl candidates that are equal modulo lifetimes.
+                        // Therefore, if we've already emitted an error, just skip this
+                        // one, since it's not particularly actionable.
+                        err.cancel();
+                        return e;
+                    }
+                    self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
+                } else {
+                    if let Some(e) = self.tainted_by_errors() {
+                        err.cancel();
+                        return e;
+                    }
+                    err.note(format!("cannot satisfy `{predicate}`"));
+                    let impl_candidates =
+                        self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
+                    if impl_candidates.len() < 40 {
+                        self.report_similar_impl_candidates(
+                            impl_candidates.as_slice(),
+                            trait_ref,
+                            obligation.cause.body_id,
+                            &mut err,
+                            false,
+                            obligation.param_env,
+                        );
+                    }
+                }
+
+                if let ObligationCauseCode::WhereClause(def_id, _)
+                | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
+                {
+                    self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
+                }
+
+                if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
+                    && let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
+                {
+                    let mut expr_finder = FindExprBySpan::new(span, self.tcx);
+                    expr_finder.visit_expr(&body.value);
+
+                    if let Some(hir::Expr {
+                        kind:
+                            hir::ExprKind::Call(
+                                hir::Expr {
+                                    kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
+                                    ..
+                                },
+                                _,
+                            )
+                            | hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
+                        ..
+                    }) = expr_finder.result
+                        && let [
+                            ..,
+                            trait_path_segment @ hir::PathSegment {
+                                res: Res::Def(DefKind::Trait, trait_id),
+                                ..
+                            },
+                            hir::PathSegment {
+                                ident: assoc_item_name,
+                                res: Res::Def(_, item_id),
+                                ..
+                            },
+                        ] = path.segments
+                        && data.trait_ref.def_id == *trait_id
+                        && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
+                        && let None = self.tainted_by_errors()
+                    {
+                        let (verb, noun) = match self.tcx.associated_item(item_id).kind {
+                            ty::AssocKind::Const => ("refer to the", "constant"),
+                            ty::AssocKind::Fn => ("call", "function"),
+                            // This is already covered by E0223, but this following single match
+                            // arm doesn't hurt here.
+                            ty::AssocKind::Type => ("refer to the", "type"),
+                        };
+
+                        // Replace the more general E0283 with a more specific error
+                        err.cancel();
+                        err = self.dcx().struct_span_err(
+                            span,
+                            format!(
+                                "cannot {verb} associated {noun} on trait without specifying the \
+                                 corresponding `impl` type",
+                            ),
+                        );
+                        err.code(E0790);
+
+                        if let Some(local_def_id) = data.trait_ref.def_id.as_local()
+                            && let hir::Node::Item(hir::Item {
+                                ident: trait_name,
+                                kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
+                                ..
+                            }) = self.tcx.hir_node_by_def_id(local_def_id)
+                            && let Some(method_ref) = trait_item_refs
+                                .iter()
+                                .find(|item_ref| item_ref.ident == *assoc_item_name)
+                        {
+                            err.span_label(
+                                method_ref.span,
+                                format!("`{trait_name}::{assoc_item_name}` defined here"),
+                            );
+                        }
+
+                        err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
+
+                        let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
+
+                        if let Some(impl_def_id) =
+                            trait_impls.non_blanket_impls().values().flatten().next()
+                        {
+                            let non_blanket_impl_count =
+                                trait_impls.non_blanket_impls().values().flatten().count();
+                            // If there is only one implementation of the trait, suggest using it.
+                            // Otherwise, use a placeholder comment for the implementation.
+                            let (message, self_type) = if non_blanket_impl_count == 1 {
+                                (
+                                    "use the fully-qualified path to the only available \
+                                     implementation",
+                                    format!(
+                                        "{}",
+                                        self.tcx.type_of(impl_def_id).instantiate_identity()
+                                    ),
+                                )
+                            } else {
+                                (
+                                    "use a fully-qualified path to a specific available \
+                                     implementation",
+                                    "/* self type */".to_string(),
+                                )
+                            };
+                            let mut suggestions =
+                                vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))];
+                            if let Some(generic_arg) = trait_path_segment.args {
+                                let between_span =
+                                    trait_path_segment.ident.span.between(generic_arg.span_ext);
+                                // get rid of :: between Trait and <type>
+                                // must be '::' between them, otherwise the parser won't accept the code
+                                suggestions.push((between_span, "".to_string()));
+                                suggestions
+                                    .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
+                            } else {
+                                suggestions.push((
+                                    trait_path_segment.ident.span.shrink_to_hi(),
+                                    ">".to_string(),
+                                ));
+                            }
+                            err.multipart_suggestion(
+                                message,
+                                suggestions,
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                };
+
+                err
+            }
+
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+                // Same hacky approach as above to avoid deluging user
+                // with error messages.
+
+                if let Err(e) = arg.error_reported() {
+                    return e;
+                }
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+
+                self.emit_inference_failure_err(
+                    obligation.cause.body_id,
+                    span,
+                    arg,
+                    TypeAnnotationNeeded::E0282,
+                    false,
+                )
+            }
+
+            ty::PredicateKind::Subtype(data) => {
+                if let Err(e) = data.error_reported() {
+                    return e;
+                }
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+                let ty::SubtypePredicate { a_is_expected: _, a, b } = data;
+                // both must be type variables, or the other would've been instantiated
+                assert!(a.is_ty_var() && b.is_ty_var());
+                self.emit_inference_failure_err(
+                    obligation.cause.body_id,
+                    span,
+                    a.into(),
+                    TypeAnnotationNeeded::E0282,
+                    true,
+                )
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
+                if let Err(e) = predicate.error_reported() {
+                    return e;
+                }
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+
+                if let Err(guar) =
+                    self.tcx.ensure().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.
+                    return guar;
+                }
+                let arg = data
+                    .projection_term
+                    .args
+                    .iter()
+                    .chain(Some(data.term.into_arg()))
+                    .find(|g| g.has_non_region_infer());
+                if let Some(arg) = arg {
+                    self.emit_inference_failure_err(
+                        obligation.cause.body_id,
+                        span,
+                        arg,
+                        TypeAnnotationNeeded::E0284,
+                        true,
+                    )
+                    .with_note(format!("cannot satisfy `{predicate}`"))
+                } else {
+                    // If we can't find a generic parameter, just print a generic error
+                    struct_span_code_err!(
+                        self.dcx(),
+                        span,
+                        E0284,
+                        "type annotations needed: cannot satisfy `{}`",
+                        predicate,
+                    )
+                    .with_span_label(span, format!("cannot satisfy `{predicate}`"))
+                }
+            }
+
+            ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
+                if let Err(e) = predicate.error_reported() {
+                    return e;
+                }
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+                let arg = data.walk().find(|g| g.is_non_region_infer());
+                if let Some(arg) = arg {
+                    let err = self.emit_inference_failure_err(
+                        obligation.cause.body_id,
+                        span,
+                        arg,
+                        TypeAnnotationNeeded::E0284,
+                        true,
+                    );
+                    err
+                } else {
+                    // If we can't find a generic parameter, just print a generic error
+                    struct_span_code_err!(
+                        self.dcx(),
+                        span,
+                        E0284,
+                        "type annotations needed: cannot satisfy `{}`",
+                        predicate,
+                    )
+                    .with_span_label(span, format!("cannot satisfy `{predicate}`"))
+                }
+            }
+
+            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self
+                .emit_inference_failure_err(
+                    obligation.cause.body_id,
+                    span,
+                    ct.into(),
+                    TypeAnnotationNeeded::E0284,
+                    true,
+                ),
+            ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
+                if term.is_infer() =>
+            {
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+                struct_span_code_err!(
+                    self.dcx(),
+                    span,
+                    E0284,
+                    "type annotations needed: cannot normalize `{alias}`",
+                )
+                .with_span_label(span, format!("cannot normalize `{alias}`"))
+            }
+
+            _ => {
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+                struct_span_code_err!(
+                    self.dcx(),
+                    span,
+                    E0284,
+                    "type annotations needed: cannot satisfy `{}`",
+                    predicate,
+                )
+                .with_span_label(span, format!("cannot satisfy `{predicate}`"))
+            }
+        };
+        self.note_obligation_cause(&mut err, obligation);
+        err.emit()
+    }
+
+    fn annotate_source_of_ambiguity(
+        &self,
+        err: &mut Diag<'_>,
+        ambiguities: &[CandidateSource],
+        predicate: ty::Predicate<'tcx>,
+    ) {
+        let mut spans = vec![];
+        let mut crates = vec![];
+        let mut post = vec![];
+        let mut has_param_env = false;
+        for ambiguity in ambiguities {
+            match ambiguity {
+                CandidateSource::DefId(impl_def_id) => match self.tcx.span_of_impl(*impl_def_id) {
+                    Ok(span) => spans.push(span),
+                    Err(name) => {
+                        crates.push(name);
+                        if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
+                            post.push(header);
+                        }
+                    }
+                },
+                CandidateSource::ParamEnv(span) => {
+                    has_param_env = true;
+                    spans.push(*span);
+                }
+            }
+        }
+        let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
+        crate_names.sort();
+        crate_names.dedup();
+        post.sort();
+        post.dedup();
+
+        if self.tainted_by_errors().is_some()
+            && (crate_names.len() == 1
+                && spans.len() == 0
+                && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
+                || predicate.visit_with(&mut HasNumericInferVisitor).is_break())
+        {
+            // Avoid complaining about other inference issues for expressions like
+            // `42 >> 1`, where the types are still `{integer}`, but we want to
+            // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
+            // NOTE(eddyb) this was `.cancel()`, but `err`
+            // is borrowed, so we can't fully defuse it.
+            err.downgrade_to_delayed_bug();
+            return;
+        }
+
+        let msg = format!(
+            "multiple `impl`s{} satisfying `{}` found",
+            if has_param_env { " or `where` clauses" } else { "" },
+            predicate
+        );
+        let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+            format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),)
+        } else if post.len() == 1 {
+            format!(": `{}`", post[0])
+        } else {
+            String::new()
+        };
+
+        match (spans.len(), crates.len(), crate_names.len()) {
+            (0, 0, 0) => {
+                err.note(format!("cannot satisfy `{predicate}`"));
+            }
+            (0, _, 1) => {
+                err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
+            }
+            (0, _, _) => {
+                err.note(format!(
+                    "{} in the following crates: {}{}",
+                    msg,
+                    crate_names.join(", "),
+                    post,
+                ));
+            }
+            (_, 0, 0) => {
+                let span: MultiSpan = spans.into();
+                err.span_note(span, msg);
+            }
+            (_, 1, 1) => {
+                let span: MultiSpan = spans.into();
+                err.span_note(span, msg);
+                err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,));
+            }
+            _ => {
+                let span: MultiSpan = spans.into();
+                err.span_note(span, msg);
+                err.note(format!(
+                    "and more `impl`s found in the following crates: {}{}",
+                    crate_names.join(", "),
+                    post,
+                ));
+            }
+        }
+    }
+}
+
+struct HasNumericInferVisitor;
+
+impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor {
+    type Result = ControlFlow<()>;
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
+        if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index adf1076a7c9..f7ec5f1ff32 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1,34 +1,30 @@
-// ignore-tidy-filelength :(
-
 use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
 use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _};
+use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt;
 use crate::errors::{
     AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
 };
-use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
+use crate::infer::error_reporting::TyCategory;
 use crate::infer::InferCtxtExt as _;
 use crate::infer::{self, InferCtxt};
-use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt;
-use crate::traits::error_reporting::{ambiguity, ambiguity::CandidateSource::*};
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::specialize::to_pretty_impl_header;
 use crate::traits::NormalizeExt;
 use crate::traits::{
-    elaborate, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation,
-    ObligationCause, ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation,
-    SelectionError, SignatureMismatch, TraitNotObjectSafe,
+    elaborate, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
+    ObligationCtxt, Overflow, PredicateObligation, SelectionError, SignatureMismatch,
+    TraitNotObjectSafe,
 };
 use core::ops::ControlFlow;
-use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
-use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart};
-use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey};
-use rustc_hir::def::{DefKind, Namespace, Res};
+use rustc_errors::{pluralize, struct_span_code_err, Applicability, StringPart};
+use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
+use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::Node;
 use rustc_hir::{self as hir, LangItem};
-use rustc_hir::{GenericParam, Item, Node};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::{InferOk, TypeTrace};
 use rustc_macros::extension;
@@ -42,323 +38,21 @@ use rustc_middle::ty::print::{
     PrintTraitRefExt as _,
 };
 use rustc_middle::ty::{
-    self, SubtypePredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable,
-    TypeVisitableExt, Upcast,
+    self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast,
 };
 use rustc_middle::{bug, span_bug};
-use rustc_session::Limit;
-use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::sym;
-use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP};
+use rustc_span::{BytePos, Span, Symbol, DUMMY_SP};
 use std::borrow::Cow;
-use std::fmt;
-use std::iter;
 
 use super::{
-    ArgKind, CandidateSimilarity, FindExprBySpan, FindTypeParam, GetSafeTransmuteErrorAndReason,
-    HasNumericInferVisitor, ImplCandidate, UnsatisfiedConst,
+    ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst,
 };
 
 pub use rustc_infer::traits::error_reporting::*;
 
-pub enum OverflowCause<'tcx> {
-    DeeplyNormalize(ty::AliasTerm<'tcx>),
-    TraitSolver(ty::Predicate<'tcx>),
-}
-
-pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
-    tcx: TyCtxt<'tcx>,
-    err: &mut Diag<'_, G>,
-) {
-    let suggested_limit = match tcx.recursion_limit() {
-        Limit(0) => Limit(2),
-        limit => limit * 2,
-    };
-    err.help(format!(
-        "consider increasing the recursion limit by adding a \
-         `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
-        suggested_limit,
-        tcx.crate_name(LOCAL_CRATE),
-    ));
-}
-
-#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)]
+#[extension(pub trait TypeErrCtxtSelectionErrExt<'a, 'tcx>)]
 impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
-    fn report_fulfillment_errors(
-        &self,
-        mut errors: Vec<FulfillmentError<'tcx>>,
-    ) -> ErrorGuaranteed {
-        self.sub_relations
-            .borrow_mut()
-            .add_constraints(self, errors.iter().map(|e| e.obligation.predicate));
-
-        #[derive(Debug)]
-        struct ErrorDescriptor<'tcx> {
-            predicate: ty::Predicate<'tcx>,
-            index: Option<usize>, // None if this is an old error
-        }
-
-        let mut error_map: FxIndexMap<_, Vec<_>> = self
-            .reported_trait_errors
-            .borrow()
-            .iter()
-            .map(|(&span, predicates)| {
-                (
-                    span,
-                    predicates
-                        .0
-                        .iter()
-                        .map(|&predicate| ErrorDescriptor { predicate, index: None })
-                        .collect(),
-                )
-            })
-            .collect();
-
-        // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics
-        // with more relevant type information and hide redundant E0282 errors.
-        errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
-                if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) =>
-            {
-                1
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
-            ty::PredicateKind::Coerce(_) => 2,
-            _ => 0,
-        });
-
-        for (index, error) in errors.iter().enumerate() {
-            // We want to ignore desugarings here: spans are equivalent even
-            // if one is the result of a desugaring and the other is not.
-            let mut span = error.obligation.cause.span;
-            let expn_data = span.ctxt().outer_expn_data();
-            if let ExpnKind::Desugaring(_) = expn_data.kind {
-                span = expn_data.call_site;
-            }
-
-            error_map.entry(span).or_default().push(ErrorDescriptor {
-                predicate: error.obligation.predicate,
-                index: Some(index),
-            });
-        }
-
-        // We do this in 2 passes because we want to display errors in order, though
-        // maybe it *is* better to sort errors by span or something.
-        let mut is_suppressed = vec![false; errors.len()];
-        for (_, error_set) in error_map.iter() {
-            // We want to suppress "duplicate" errors with the same span.
-            for error in error_set {
-                if let Some(index) = error.index {
-                    // Suppress errors that are either:
-                    // 1) strictly implied by another error.
-                    // 2) implied by an error with a smaller index.
-                    for error2 in error_set {
-                        if error2.index.is_some_and(|index2| is_suppressed[index2]) {
-                            // Avoid errors being suppressed by already-suppressed
-                            // errors, to prevent all errors from being suppressed
-                            // at once.
-                            continue;
-                        }
-
-                        if self.error_implies(error2.predicate, error.predicate)
-                            && !(error2.index >= error.index
-                                && self.error_implies(error.predicate, error2.predicate))
-                        {
-                            info!("skipping {:?} (implied by {:?})", error, error2);
-                            is_suppressed[index] = true;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        let mut reported = None;
-
-        for from_expansion in [false, true] {
-            for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
-                if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
-                    let guar = self.report_fulfillment_error(error);
-                    self.infcx.set_tainted_by_errors(guar);
-                    reported = Some(guar);
-                    // We want to ignore desugarings here: spans are equivalent even
-                    // if one is the result of a desugaring and the other is not.
-                    let mut span = error.obligation.cause.span;
-                    let expn_data = span.ctxt().outer_expn_data();
-                    if let ExpnKind::Desugaring(_) = expn_data.kind {
-                        span = expn_data.call_site;
-                    }
-                    self.reported_trait_errors
-                        .borrow_mut()
-                        .entry(span)
-                        .or_insert_with(|| (vec![], guar))
-                        .0
-                        .push(error.obligation.predicate);
-                }
-            }
-        }
-
-        // It could be that we don't report an error because we have seen an `ErrorReported` from
-        // another source. We should probably be able to fix most of these, but some are delayed
-        // bugs that get a proper error after this function.
-        reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
-    }
-
-    /// Reports that an overflow has occurred and halts compilation. We
-    /// halt compilation unconditionally because it is important that
-    /// overflows never be masked -- they basically represent computations
-    /// whose result could not be truly determined and thus we can't say
-    /// if the program type checks or not -- and they are unusual
-    /// occurrences in any case.
-    fn report_overflow_error(
-        &self,
-        cause: OverflowCause<'tcx>,
-        span: Span,
-        suggest_increasing_limit: bool,
-        mutate: impl FnOnce(&mut Diag<'_>),
-    ) -> ! {
-        let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
-        mutate(&mut err);
-        err.emit();
-        FatalError.raise();
-    }
-
-    fn build_overflow_error(
-        &self,
-        cause: OverflowCause<'tcx>,
-        span: Span,
-        suggest_increasing_limit: bool,
-    ) -> Diag<'a> {
-        fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
-        where
-            T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
-        {
-            let s = value.to_string();
-            if s.len() > 50 {
-                // We don't need to save the type to a file, we will be talking about this type already
-                // in a separate note when we explain the obligation, so it will be available that way.
-                let mut cx: FmtPrinter<'_, '_> =
-                    FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6));
-                value.print(&mut cx).unwrap();
-                cx.into_buffer()
-            } else {
-                s
-            }
-        }
-
-        let mut err = match cause {
-            OverflowCause::DeeplyNormalize(alias_term) => {
-                let alias_term = self.resolve_vars_if_possible(alias_term);
-                let kind = alias_term.kind(self.tcx).descr();
-                let alias_str = with_short_path(self.tcx, alias_term);
-                struct_span_code_err!(
-                    self.dcx(),
-                    span,
-                    E0275,
-                    "overflow normalizing the {kind} `{alias_str}`",
-                )
-            }
-            OverflowCause::TraitSolver(predicate) => {
-                let predicate = self.resolve_vars_if_possible(predicate);
-                match predicate.kind().skip_binder() {
-                    ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ })
-                    | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
-                        struct_span_code_err!(
-                            self.dcx(),
-                            span,
-                            E0275,
-                            "overflow assigning `{a}` to `{b}`",
-                        )
-                    }
-                    _ => {
-                        let pred_str = with_short_path(self.tcx, predicate);
-                        struct_span_code_err!(
-                            self.dcx(),
-                            span,
-                            E0275,
-                            "overflow evaluating the requirement `{pred_str}`",
-                        )
-                    }
-                }
-            }
-        };
-
-        if suggest_increasing_limit {
-            suggest_new_overflow_limit(self.tcx, &mut err);
-        }
-
-        err
-    }
-
-    /// Reports that an overflow has occurred and halts compilation. We
-    /// halt compilation unconditionally because it is important that
-    /// overflows never be masked -- they basically represent computations
-    /// whose result could not be truly determined and thus we can't say
-    /// if the program type checks or not -- and they are unusual
-    /// occurrences in any case.
-    fn report_overflow_obligation<T>(
-        &self,
-        obligation: &Obligation<'tcx, T>,
-        suggest_increasing_limit: bool,
-    ) -> !
-    where
-        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
-    {
-        let predicate = obligation.predicate.clone().upcast(self.tcx);
-        let predicate = self.resolve_vars_if_possible(predicate);
-        self.report_overflow_error(
-            OverflowCause::TraitSolver(predicate),
-            obligation.cause.span,
-            suggest_increasing_limit,
-            |err| {
-                self.note_obligation_cause_code(
-                    obligation.cause.body_id,
-                    err,
-                    predicate,
-                    obligation.param_env,
-                    obligation.cause.code(),
-                    &mut vec![],
-                    &mut Default::default(),
-                );
-            },
-        );
-    }
-
-    /// Reports that a cycle was detected which led to overflow and halts
-    /// compilation. This is equivalent to `report_overflow_obligation` except
-    /// that we can give a more helpful error message (and, in particular,
-    /// we do not suggest increasing the overflow limit, which is not
-    /// going to help).
-    fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
-        let cycle = self.resolve_vars_if_possible(cycle.to_owned());
-        assert!(!cycle.is_empty());
-
-        debug!(?cycle, "report_overflow_error_cycle");
-
-        // The 'deepest' obligation is most likely to have a useful
-        // cause 'backtrace'
-        self.report_overflow_obligation(
-            cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
-            false,
-        );
-    }
-
-    fn report_overflow_no_abort(
-        &self,
-        obligation: PredicateObligation<'tcx>,
-        suggest_increasing_limit: bool,
-    ) -> ErrorGuaranteed {
-        let obligation = self.resolve_vars_if_possible(obligation);
-        let mut err = self.build_overflow_error(
-            OverflowCause::TraitSolver(obligation.predicate),
-            obligation.cause.span,
-            suggest_increasing_limit,
-        );
-        self.note_obligation_cause(&mut err, &obligation);
-        self.point_at_returns_when_relevant(&mut err, &obligation);
-        err.emit()
-    }
-
     /// The `root_obligation` parameter should be the `root_obligation` field
     /// from a `FulfillmentError`. If no `FulfillmentError` is available,
     /// then it should be the same as `obligation`.
@@ -986,7 +680,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         self.point_at_returns_when_relevant(&mut err, &obligation);
         err.emit()
     }
+}
 
+#[extension(pub(super) trait TypeErrCtxtExt<'a, 'tcx>)]
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     fn apply_do_not_recommend(&self, obligation: &mut PredicateObligation<'tcx>) -> bool {
         let mut base_cause = obligation.cause.code().clone();
         let mut applied_do_not_recommend = false;
@@ -1073,7 +770,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             // mismatched, then we have a totally different error to report.
             if self.enter_forall(found_args, |found_args| {
                 self.enter_forall(expected_args, |expected_args| {
-                    !self.can_sub(obligation.param_env, expected_args, found_args)
+                    !self.can_eq(obligation.param_env, expected_args, found_args)
                 })
             }) {
                 return None;
@@ -1134,7 +831,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     }
 
     /// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,
-    /// identify thoe method chain sub-expressions that could or could not have been annotated
+    /// identify those method chain sub-expressions that could or could not have been annotated
     /// with `?`.
     fn try_conversion_context(
         &self,
@@ -1296,7 +993,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     expr = binding_expr;
                 }
                 if let hir::Node::Param(_param) = parent {
-                    // ...and it is a an fn argument.
+                    // ...and it is an fn argument.
                     break;
                 }
             }
@@ -1507,72 +1204,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self), level = "debug")]
-    fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
-        let mut error = FulfillmentError {
-            obligation: error.obligation.clone(),
-            code: error.code.clone(),
-            root_obligation: error.root_obligation.clone(),
-        };
-        if matches!(
-            error.code,
-            FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
-                | FulfillmentErrorCode::Project(_)
-        ) && self.apply_do_not_recommend(&mut error.obligation)
-        {
-            error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
-        }
-
-        match error.code {
-            FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
-                error.obligation.clone(),
-                &error.root_obligation,
-                selection_error,
-            ),
-            FulfillmentErrorCode::Project(ref e) => {
-                self.report_projection_error(&error.obligation, e)
-            }
-            FulfillmentErrorCode::Ambiguity { overflow: None } => {
-                self.maybe_report_ambiguity(&error.obligation)
-            }
-            FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
-                self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
-            }
-            FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
-                .report_mismatched_types(
-                    &error.obligation.cause,
-                    expected_found.expected,
-                    expected_found.found,
-                    *err,
-                )
-                .emit(),
-            FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
-                let mut diag = self.report_mismatched_consts(
-                    &error.obligation.cause,
-                    expected_found.expected,
-                    expected_found.found,
-                    *err,
-                );
-                let code = error.obligation.cause.code().peel_derives().peel_match_impls();
-                if let ObligationCauseCode::WhereClause(..)
-                | ObligationCauseCode::WhereClauseInExpr(..) = code
-                {
-                    self.note_obligation_cause_code(
-                        error.obligation.cause.body_id,
-                        &mut diag,
-                        error.obligation.predicate,
-                        error.obligation.param_env,
-                        code,
-                        &mut vec![],
-                        &mut Default::default(),
-                    );
-                }
-                diag.emit()
-            }
-            FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
-        }
-    }
-
     #[instrument(level = "debug", skip_all)]
     fn report_projection_error(
         &self,
@@ -1586,60 +1217,113 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
 
         self.probe(|_| {
-            let ocx = ObligationCtxt::new(self);
-
             // try to find the mismatched types to report the error with.
             //
             // this can fail if the problem was higher-ranked, in which
             // cause I have no idea for a good error message.
             let bound_predicate = predicate.kind();
-            let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) =
-                bound_predicate.skip_binder()
-            {
-                let data = self.instantiate_binder_with_fresh_vars(
-                    obligation.cause.span,
-                    infer::BoundRegionConversionTime::HigherRankedType,
-                    bound_predicate.rebind(data),
-                );
-                let unnormalized_term = data.projection_term.to_term(self.tcx);
-                // FIXME(-Znext-solver): For diagnostic purposes, it would be nice
-                // to deeply normalize this type.
-                let normalized_term =
-                    ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
-
-                debug!(?obligation.cause, ?obligation.param_env);
-
-                debug!(?normalized_term, data.ty = ?data.term);
+            let (values, err) = match bound_predicate.skip_binder() {
+                ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
+                    let ocx = ObligationCtxt::new(self);
+
+                    let data = self.instantiate_binder_with_fresh_vars(
+                        obligation.cause.span,
+                        infer::BoundRegionConversionTime::HigherRankedType,
+                        bound_predicate.rebind(data),
+                    );
+                    let unnormalized_term = data.projection_term.to_term(self.tcx);
+                    // FIXME(-Znext-solver): For diagnostic purposes, it would be nice
+                    // to deeply normalize this type.
+                    let normalized_term =
+                        ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
+
+                    let is_normalized_term_expected = !matches!(
+                        obligation.cause.code().peel_derives(),
+                        ObligationCauseCode::WhereClause(..)
+                            | ObligationCauseCode::WhereClauseInExpr(..)
+                            | ObligationCauseCode::Coercion { .. }
+                    );
 
-                let is_normalized_term_expected = !matches!(
-                    obligation.cause.code().peel_derives(),
-                    |ObligationCauseCode::WhereClause(..)| ObligationCauseCode::WhereClauseInExpr(
-                        ..
-                    ) | ObligationCauseCode::Coercion { .. }
-                );
+                    let (expected, actual) = if is_normalized_term_expected {
+                        (normalized_term, data.term)
+                    } else {
+                        (data.term, normalized_term)
+                    };
 
-                let (expected, actual) = if is_normalized_term_expected {
-                    (normalized_term, data.term)
-                } else {
-                    (data.term, normalized_term)
-                };
+                    // constrain inference variables a bit more to nested obligations from normalize so
+                    // we can have more helpful errors.
+                    //
+                    // we intentionally drop errors from normalization here,
+                    // since the normalization is just done to improve the error message.
+                    let _ = ocx.select_where_possible();
 
-                // constrain inference variables a bit more to nested obligations from normalize so
-                // we can have more helpful errors.
-                //
-                // we intentionally drop errors from normalization here,
-                // since the normalization is just done to improve the error message.
-                let _ = ocx.select_where_possible();
+                    if let Err(new_err) =
+                        ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
+                    {
+                        (
+                            Some((
+                                data.projection_term,
+                                is_normalized_term_expected,
+                                self.resolve_vars_if_possible(normalized_term),
+                                data.term,
+                            )),
+                            new_err,
+                        )
+                    } else {
+                        (None, error.err)
+                    }
+                }
+                ty::PredicateKind::AliasRelate(lhs, rhs, _) => {
+                    let derive_better_type_error =
+                        |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| {
+                            let ocx = ObligationCtxt::new(self);
+                            let normalized_term = match expected_term.unpack() {
+                                ty::TermKind::Ty(_) => self.next_ty_var(DUMMY_SP).into(),
+                                ty::TermKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
+                            };
+                            ocx.register_obligation(Obligation::new(
+                                self.tcx,
+                                ObligationCause::dummy(),
+                                obligation.param_env,
+                                ty::PredicateKind::NormalizesTo(ty::NormalizesTo {
+                                    alias: alias_term,
+                                    term: normalized_term,
+                                }),
+                            ));
+                            let _ = ocx.select_where_possible();
+                            if let Err(terr) = ocx.eq(
+                                &ObligationCause::dummy(),
+                                obligation.param_env,
+                                expected_term,
+                                normalized_term,
+                            ) {
+                                Some((terr, self.resolve_vars_if_possible(normalized_term)))
+                            } else {
+                                None
+                            }
+                        };
 
-                if let Err(new_err) =
-                    ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
-                {
-                    (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
-                } else {
-                    (None, error.err)
+                    if let Some(lhs) = lhs.to_alias_term()
+                        && let Some((better_type_err, expected_term)) =
+                            derive_better_type_error(lhs, rhs)
+                    {
+                        (
+                            Some((lhs, true, self.resolve_vars_if_possible(expected_term), rhs)),
+                            better_type_err,
+                        )
+                    } else if let Some(rhs) = rhs.to_alias_term()
+                        && let Some((better_type_err, expected_term)) =
+                            derive_better_type_error(rhs, lhs)
+                    {
+                        (
+                            Some((rhs, true, self.resolve_vars_if_possible(expected_term), lhs)),
+                            better_type_err,
+                        )
+                    } else {
+                        (None, error.err)
+                    }
                 }
-            } else {
-                (None, error.err)
+                _ => (None, error.err),
             };
 
             let msg = values
@@ -1737,15 +1421,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
     fn maybe_detailed_projection_msg(
         &self,
-        pred: ty::ProjectionPredicate<'tcx>,
+        projection_term: ty::AliasTerm<'tcx>,
         normalized_ty: ty::Term<'tcx>,
         expected_ty: ty::Term<'tcx>,
     ) -> Option<String> {
-        let trait_def_id = pred.projection_term.trait_def_id(self.tcx);
-        let self_ty = pred.projection_term.self_ty();
+        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(pred.projection_term.def_id,LangItem::FnOnceOutput) {
+            if self.tcx.is_lang_item(projection_term.def_id, LangItem::FnOnceOutput) {
                 let fn_kind = self_ty.prefix_string(self.tcx);
                 let item = match self_ty.kind() {
                     ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
@@ -2297,536 +1981,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
     }
 
-    #[instrument(skip(self), level = "debug")]
-    fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed {
-        // Unable to successfully determine, probably means
-        // insufficient type information, but could mean
-        // ambiguous impls. The latter *ought* to be a
-        // coherence violation, so we don't report it here.
-
-        let predicate = self.resolve_vars_if_possible(obligation.predicate);
-        let span = obligation.cause.span;
-
-        debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
-
-        // Ambiguity errors are often caused as fallout from earlier errors.
-        // We ignore them if this `infcx` is tainted in some cases below.
-
-        let bound_predicate = predicate.kind();
-        let mut err = match bound_predicate.skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
-                let trait_ref = bound_predicate.rebind(data.trait_ref);
-                debug!(?trait_ref);
-
-                if let Err(e) = predicate.error_reported() {
-                    return e;
-                }
-
-                if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) {
-                    // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
-                    // other `Foo` impls are incoherent.
-                    return guar;
-                }
-
-                // This is kind of a hack: it frequently happens that some earlier
-                // error prevents types from being fully inferred, and then we get
-                // a bunch of uninteresting errors saying something like "<generic
-                // #0> doesn't implement Sized". It may even be true that we
-                // could just skip over all checks where the self-ty is an
-                // inference variable, but I was afraid that there might be an
-                // inference variable created, registered as an obligation, and
-                // then never forced by writeback, and hence by skipping here we'd
-                // be ignoring the fact that we don't KNOW the type works
-                // out. Though even that would probably be harmless, given that
-                // we're only talking about builtin traits, which are known to be
-                // inhabited. We used to check for `self.tcx.sess.has_errors()` to
-                // avoid inundating the user with unnecessary errors, but we now
-                // check upstream for type errors and don't add the obligations to
-                // begin with in those cases.
-                if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
-                    match self.tainted_by_errors() {
-                        None => {
-                            let err = self.emit_inference_failure_err(
-                                obligation.cause.body_id,
-                                span,
-                                trait_ref.self_ty().skip_binder().into(),
-                                ErrorCode::E0282,
-                                false,
-                            );
-                            return err.stash(span, StashKey::MaybeForgetReturn).unwrap();
-                        }
-                        Some(e) => return e,
-                    }
-                }
-
-                // Typically, this ambiguity should only happen if
-                // there are unresolved type inference variables
-                // (otherwise it would suggest a coherence
-                // failure). But given #21974 that is not necessarily
-                // the case -- we can have multiple where clauses that
-                // are only distinguished by a region, which results
-                // in an ambiguity even when all types are fully
-                // known, since we don't dispatch based on region
-                // relationships.
-
-                // Pick the first generic parameter that still contains inference variables as the one
-                // we're going to emit an error for. If there are none (see above), fall back to
-                // a more general error.
-                let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer());
-
-                let mut err = if let Some(arg) = arg {
-                    self.emit_inference_failure_err(
-                        obligation.cause.body_id,
-                        span,
-                        arg,
-                        ErrorCode::E0283,
-                        true,
-                    )
-                } else {
-                    struct_span_code_err!(
-                        self.dcx(),
-                        span,
-                        E0283,
-                        "type annotations needed: cannot satisfy `{}`",
-                        predicate,
-                    )
-                };
-
-                let mut ambiguities = ambiguity::compute_applicable_impls_for_diagnostics(
-                    self.infcx,
-                    &obligation.with(self.tcx, trait_ref),
-                );
-                let has_non_region_infer =
-                    trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
-                // It doesn't make sense to talk about applicable impls if there are more than a
-                // handful of them. If there are a lot of them, but only a few of them have no type
-                // params, we only show those, as they are more likely to be useful/intended.
-                if ambiguities.len() > 5 {
-                    let infcx = self.infcx;
-                    if !ambiguities.iter().all(|option| match option {
-                        DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
-                        ParamEnv(_) => true,
-                    }) {
-                        // If not all are blanket impls, we filter blanked impls out.
-                        ambiguities.retain(|option| match option {
-                            DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
-                            ParamEnv(_) => true,
-                        });
-                    }
-                }
-                if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
-                    if let Some(e) = self.tainted_by_errors()
-                        && arg.is_none()
-                    {
-                        // If `arg.is_none()`, then this is probably two param-env
-                        // candidates or impl candidates that are equal modulo lifetimes.
-                        // Therefore, if we've already emitted an error, just skip this
-                        // one, since it's not particularly actionable.
-                        err.cancel();
-                        return e;
-                    }
-                    self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
-                } else {
-                    if let Some(e) = self.tainted_by_errors() {
-                        err.cancel();
-                        return e;
-                    }
-                    err.note(format!("cannot satisfy `{predicate}`"));
-                    let impl_candidates =
-                        self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
-                    if impl_candidates.len() < 40 {
-                        self.report_similar_impl_candidates(
-                            impl_candidates.as_slice(),
-                            trait_ref,
-                            obligation.cause.body_id,
-                            &mut err,
-                            false,
-                            obligation.param_env,
-                        );
-                    }
-                }
-
-                if let ObligationCauseCode::WhereClause(def_id, _)
-                | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
-                {
-                    self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
-                }
-
-                if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
-                    && let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
-                {
-                    let mut expr_finder = FindExprBySpan::new(span, self.tcx);
-                    expr_finder.visit_expr(&body.value);
-
-                    if let Some(hir::Expr {
-                        kind:
-                            hir::ExprKind::Call(
-                                hir::Expr {
-                                    kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
-                                    ..
-                                },
-                                _,
-                            )
-                            | hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
-                        ..
-                    }) = expr_finder.result
-                        && let [
-                            ..,
-                            trait_path_segment @ hir::PathSegment {
-                                res: Res::Def(DefKind::Trait, trait_id),
-                                ..
-                            },
-                            hir::PathSegment {
-                                ident: assoc_item_name,
-                                res: Res::Def(_, item_id),
-                                ..
-                            },
-                        ] = path.segments
-                        && data.trait_ref.def_id == *trait_id
-                        && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
-                        && let None = self.tainted_by_errors()
-                    {
-                        let (verb, noun) = match self.tcx.associated_item(item_id).kind {
-                            ty::AssocKind::Const => ("refer to the", "constant"),
-                            ty::AssocKind::Fn => ("call", "function"),
-                            // This is already covered by E0223, but this following single match
-                            // arm doesn't hurt here.
-                            ty::AssocKind::Type => ("refer to the", "type"),
-                        };
-
-                        // Replace the more general E0283 with a more specific error
-                        err.cancel();
-                        err = self.dcx().struct_span_err(
-                            span,
-                            format!(
-                                "cannot {verb} associated {noun} on trait without specifying the \
-                                 corresponding `impl` type",
-                            ),
-                        );
-                        err.code(E0790);
-
-                        if let Some(local_def_id) = data.trait_ref.def_id.as_local()
-                            && let hir::Node::Item(hir::Item {
-                                ident: trait_name,
-                                kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
-                                ..
-                            }) = self.tcx.hir_node_by_def_id(local_def_id)
-                            && let Some(method_ref) = trait_item_refs
-                                .iter()
-                                .find(|item_ref| item_ref.ident == *assoc_item_name)
-                        {
-                            err.span_label(
-                                method_ref.span,
-                                format!("`{trait_name}::{assoc_item_name}` defined here"),
-                            );
-                        }
-
-                        err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
-
-                        let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
-
-                        if let Some(impl_def_id) =
-                            trait_impls.non_blanket_impls().values().flatten().next()
-                        {
-                            let non_blanket_impl_count =
-                                trait_impls.non_blanket_impls().values().flatten().count();
-                            // If there is only one implementation of the trait, suggest using it.
-                            // Otherwise, use a placeholder comment for the implementation.
-                            let (message, self_type) = if non_blanket_impl_count == 1 {
-                                (
-                                    "use the fully-qualified path to the only available \
-                                     implementation",
-                                    format!(
-                                        "{}",
-                                        self.tcx.type_of(impl_def_id).instantiate_identity()
-                                    ),
-                                )
-                            } else {
-                                (
-                                    "use a fully-qualified path to a specific available \
-                                     implementation",
-                                    "/* self type */".to_string(),
-                                )
-                            };
-                            let mut suggestions =
-                                vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))];
-                            if let Some(generic_arg) = trait_path_segment.args {
-                                let between_span =
-                                    trait_path_segment.ident.span.between(generic_arg.span_ext);
-                                // get rid of :: between Trait and <type>
-                                // must be '::' between them, otherwise the parser won't accept the code
-                                suggestions.push((between_span, "".to_string()));
-                                suggestions
-                                    .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
-                            } else {
-                                suggestions.push((
-                                    trait_path_segment.ident.span.shrink_to_hi(),
-                                    ">".to_string(),
-                                ));
-                            }
-                            err.multipart_suggestion(
-                                message,
-                                suggestions,
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                };
-
-                err
-            }
-
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
-                // Same hacky approach as above to avoid deluging user
-                // with error messages.
-
-                if let Err(e) = arg.error_reported() {
-                    return e;
-                }
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-
-                self.emit_inference_failure_err(
-                    obligation.cause.body_id,
-                    span,
-                    arg,
-                    ErrorCode::E0282,
-                    false,
-                )
-            }
-
-            ty::PredicateKind::Subtype(data) => {
-                if let Err(e) = data.error_reported() {
-                    return e;
-                }
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-                let SubtypePredicate { a_is_expected: _, a, b } = data;
-                // both must be type variables, or the other would've been instantiated
-                assert!(a.is_ty_var() && b.is_ty_var());
-                self.emit_inference_failure_err(
-                    obligation.cause.body_id,
-                    span,
-                    a.into(),
-                    ErrorCode::E0282,
-                    true,
-                )
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
-                if let Err(e) = predicate.error_reported() {
-                    return e;
-                }
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-
-                if let Err(guar) =
-                    self.tcx.ensure().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.
-                    return guar;
-                }
-                let arg = data
-                    .projection_term
-                    .args
-                    .iter()
-                    .chain(Some(data.term.into_arg()))
-                    .find(|g| g.has_non_region_infer());
-                if let Some(arg) = arg {
-                    self.emit_inference_failure_err(
-                        obligation.cause.body_id,
-                        span,
-                        arg,
-                        ErrorCode::E0284,
-                        true,
-                    )
-                    .with_note(format!("cannot satisfy `{predicate}`"))
-                } else {
-                    // If we can't find a generic parameter, just print a generic error
-                    struct_span_code_err!(
-                        self.dcx(),
-                        span,
-                        E0284,
-                        "type annotations needed: cannot satisfy `{}`",
-                        predicate,
-                    )
-                    .with_span_label(span, format!("cannot satisfy `{predicate}`"))
-                }
-            }
-
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
-                if let Err(e) = predicate.error_reported() {
-                    return e;
-                }
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-                let arg = data.walk().find(|g| g.is_non_region_infer());
-                if let Some(arg) = arg {
-                    let err = self.emit_inference_failure_err(
-                        obligation.cause.body_id,
-                        span,
-                        arg,
-                        ErrorCode::E0284,
-                        true,
-                    );
-                    err
-                } else {
-                    // If we can't find a generic parameter, just print a generic error
-                    struct_span_code_err!(
-                        self.dcx(),
-                        span,
-                        E0284,
-                        "type annotations needed: cannot satisfy `{}`",
-                        predicate,
-                    )
-                    .with_span_label(span, format!("cannot satisfy `{predicate}`"))
-                }
-            }
-
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self
-                .emit_inference_failure_err(
-                    obligation.cause.body_id,
-                    span,
-                    ct.into(),
-                    ErrorCode::E0284,
-                    true,
-                ),
-            ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
-                if term.is_infer() =>
-            {
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-                struct_span_code_err!(
-                    self.dcx(),
-                    span,
-                    E0284,
-                    "type annotations needed: cannot normalize `{alias}`",
-                )
-                .with_span_label(span, format!("cannot normalize `{alias}`"))
-            }
-
-            _ => {
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-                struct_span_code_err!(
-                    self.dcx(),
-                    span,
-                    E0284,
-                    "type annotations needed: cannot satisfy `{}`",
-                    predicate,
-                )
-                .with_span_label(span, format!("cannot satisfy `{predicate}`"))
-            }
-        };
-        self.note_obligation_cause(&mut err, obligation);
-        err.emit()
-    }
-
-    fn annotate_source_of_ambiguity(
-        &self,
-        err: &mut Diag<'_>,
-        ambiguities: &[ambiguity::CandidateSource],
-        predicate: ty::Predicate<'tcx>,
-    ) {
-        let mut spans = vec![];
-        let mut crates = vec![];
-        let mut post = vec![];
-        let mut has_param_env = false;
-        for ambiguity in ambiguities {
-            match ambiguity {
-                ambiguity::CandidateSource::DefId(impl_def_id) => {
-                    match self.tcx.span_of_impl(*impl_def_id) {
-                        Ok(span) => spans.push(span),
-                        Err(name) => {
-                            crates.push(name);
-                            if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
-                                post.push(header);
-                            }
-                        }
-                    }
-                }
-                ambiguity::CandidateSource::ParamEnv(span) => {
-                    has_param_env = true;
-                    spans.push(*span);
-                }
-            }
-        }
-        let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
-        crate_names.sort();
-        crate_names.dedup();
-        post.sort();
-        post.dedup();
-
-        if self.tainted_by_errors().is_some()
-            && (crate_names.len() == 1
-                && spans.len() == 0
-                && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
-                || predicate.visit_with(&mut HasNumericInferVisitor).is_break())
-        {
-            // Avoid complaining about other inference issues for expressions like
-            // `42 >> 1`, where the types are still `{integer}`, but we want to
-            // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
-            // NOTE(eddyb) this was `.cancel()`, but `err`
-            // is borrowed, so we can't fully defuse it.
-            err.downgrade_to_delayed_bug();
-            return;
-        }
-
-        let msg = format!(
-            "multiple `impl`s{} satisfying `{}` found",
-            if has_param_env { " or `where` clauses" } else { "" },
-            predicate
-        );
-        let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
-            format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),)
-        } else if post.len() == 1 {
-            format!(": `{}`", post[0])
-        } else {
-            String::new()
-        };
-
-        match (spans.len(), crates.len(), crate_names.len()) {
-            (0, 0, 0) => {
-                err.note(format!("cannot satisfy `{predicate}`"));
-            }
-            (0, _, 1) => {
-                err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
-            }
-            (0, _, _) => {
-                err.note(format!(
-                    "{} in the following crates: {}{}",
-                    msg,
-                    crate_names.join(", "),
-                    post,
-                ));
-            }
-            (_, 0, 0) => {
-                let span: MultiSpan = spans.into();
-                err.span_note(span, msg);
-            }
-            (_, 1, 1) => {
-                let span: MultiSpan = spans.into();
-                err.span_note(span, msg);
-                err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,));
-            }
-            _ => {
-                let span: MultiSpan = spans.into();
-                err.span_note(span, msg);
-                err.note(format!(
-                    "and more `impl`s found in the following crates: {}{}",
-                    crate_names.join(", "),
-                    post,
-                ));
-            }
-        }
-    }
-
     /// Returns `true` if the trait predicate may apply for *some* assignment
     /// to the type parameters.
     fn predicate_can_apply(
@@ -2894,136 +2048,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    #[instrument(level = "debug", skip_all)]
-    fn suggest_unsized_bound_if_applicable(
-        &self,
-        err: &mut Diag<'_>,
-        obligation: &PredicateObligation<'tcx>,
-    ) {
-        let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
-            obligation.predicate.kind().skip_binder()
-        else {
-            return;
-        };
-        let (ObligationCauseCode::WhereClause(item_def_id, span)
-        | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) =
-            *obligation.cause.code().peel_derives()
-        else {
-            return;
-        };
-        if span.is_dummy() {
-            return;
-        }
-        debug!(?pred, ?item_def_id, ?span);
-
-        let (Some(node), true) = (
-            self.tcx.hir().get_if_local(item_def_id),
-            self.tcx.is_lang_item(pred.def_id(), LangItem::Sized),
-        ) else {
-            return;
-        };
-        self.maybe_suggest_unsized_generics(err, span, node);
-    }
-
-    #[instrument(level = "debug", skip_all)]
-    fn maybe_suggest_unsized_generics(&self, err: &mut Diag<'_>, span: Span, node: Node<'tcx>) {
-        let Some(generics) = node.generics() else {
-            return;
-        };
-        let sized_trait = self.tcx.lang_items().sized_trait();
-        debug!(?generics.params);
-        debug!(?generics.predicates);
-        let Some(param) = generics.params.iter().find(|param| param.span == span) else {
-            return;
-        };
-        // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
-        // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
-        let explicitly_sized = generics
-            .bounds_for_param(param.def_id)
-            .flat_map(|bp| bp.bounds)
-            .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
-        if explicitly_sized {
-            return;
-        }
-        debug!(?param);
-        match node {
-            hir::Node::Item(
-                item @ hir::Item {
-                    // Only suggest indirection for uses of type parameters in ADTs.
-                    kind:
-                        hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
-                    ..
-                },
-            ) => {
-                if self.maybe_indirection_for_unsized(err, item, param) {
-                    return;
-                }
-            }
-            _ => {}
-        };
-
-        // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
-        let (span, separator, open_paren_sp) =
-            if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
-                (s, " +", open_paren_sp)
-            } else {
-                (param.name.ident().span.shrink_to_hi(), ":", None)
-            };
-
-        let mut suggs = vec![];
-        let suggestion = format!("{separator} ?Sized");
-
-        if let Some(open_paren_sp) = open_paren_sp {
-            suggs.push((open_paren_sp, "(".to_string()));
-            suggs.push((span, format!("){suggestion}")));
-        } else {
-            suggs.push((span, suggestion));
-        }
-
-        err.multipart_suggestion_verbose(
-            "consider relaxing the implicit `Sized` restriction",
-            suggs,
-            Applicability::MachineApplicable,
-        );
-    }
-
-    fn maybe_indirection_for_unsized(
-        &self,
-        err: &mut Diag<'_>,
-        item: &Item<'tcx>,
-        param: &GenericParam<'tcx>,
-    ) -> bool {
-        // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
-        // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
-        // is not. Look for invalid "bare" parameter uses, and suggest using indirection.
-        let mut visitor =
-            FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
-        visitor.visit_item(item);
-        if visitor.invalid_spans.is_empty() {
-            return false;
-        }
-        let mut multispan: MultiSpan = param.span.into();
-        multispan.push_span_label(
-            param.span,
-            format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
-        );
-        for sp in visitor.invalid_spans {
-            multispan.push_span_label(
-                sp,
-                format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
-            );
-        }
-        err.span_help(
-            multispan,
-            format!(
-                "you could relax the implicit `Sized` bound on `{T}` if it were \
-                used through indirection like `&{T}` or `Box<{T}>`",
-                T = param.name.ident(),
-            ),
-        );
-        true
-    }
-
     fn is_recursive_obligation(
         &self,
         obligated_types: &mut Vec<Ty<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/infer_ctxt_ext.rs
index 34da8e576ce..e8d7e80ac56 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/infer_ctxt_ext.rs
@@ -1,3 +1,5 @@
+// FIXME(error_reporting): This should be made into private methods on `TypeErrCtxt`.
+
 use crate::infer::InferCtxt;
 use crate::traits::{Obligation, ObligationCause, ObligationCtxt};
 use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag};
@@ -9,8 +11,6 @@ use rustc_span::{Span, DUMMY_SP};
 
 use super::ArgKind;
 
-pub use rustc_infer::traits::error_reporting::*;
-
 #[extension(pub trait InferCtxtExt<'tcx>)]
 impl<'tcx> InferCtxt<'tcx> {
     /// Given some node representing a fn-like thing in the HIR map,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
new file mode 100644
index 00000000000..2131e236401
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -0,0 +1,385 @@
+pub mod ambiguity;
+mod fulfillment_errors;
+mod infer_ctxt_ext;
+pub mod on_unimplemented;
+mod overflow;
+pub mod suggestions;
+
+use std::iter;
+
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{self as hir, LangItem};
+use rustc_infer::infer::error_reporting::TypeErrCtxt;
+use rustc_infer::traits::{
+    Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError,
+};
+use rustc_macros::extension;
+use rustc_middle::ty::print::PrintTraitRefExt as _;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::{ErrorGuaranteed, ExpnKind, Span};
+
+use ambiguity::TypeErrCtxtAmbiguityExt as _;
+use fulfillment_errors::TypeErrCtxtExt as _;
+use suggestions::TypeErrCtxtExt as _;
+
+use crate::traits::{FulfillmentError, FulfillmentErrorCode};
+
+pub use self::fulfillment_errors::*;
+pub use self::infer_ctxt_ext::*;
+pub use self::overflow::*;
+
+// When outputting impl candidates, prefer showing those that are more similar.
+//
+// We also compare candidates after skipping lifetimes, which has a lower
+// priority than exact matches.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum CandidateSimilarity {
+    Exact { ignoring_lifetimes: bool },
+    Fuzzy { ignoring_lifetimes: bool },
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct ImplCandidate<'tcx> {
+    pub trait_ref: ty::TraitRef<'tcx>,
+    pub similarity: CandidateSimilarity,
+    impl_def_id: DefId,
+}
+
+enum GetSafeTransmuteErrorAndReason {
+    Silent,
+    Error { err_msg: String, safe_transmute_explanation: Option<String> },
+}
+
+struct UnsatisfiedConst(pub bool);
+
+/// Crude way of getting back an `Expr` from a `Span`.
+pub struct FindExprBySpan<'hir> {
+    pub span: Span,
+    pub result: Option<&'hir hir::Expr<'hir>>,
+    pub ty_result: Option<&'hir hir::Ty<'hir>>,
+    pub include_closures: bool,
+    pub tcx: TyCtxt<'hir>,
+}
+
+impl<'hir> FindExprBySpan<'hir> {
+    pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self {
+        Self { span, result: None, ty_result: None, tcx, include_closures: false }
+    }
+}
+
+impl<'v> Visitor<'v> for FindExprBySpan<'v> {
+    type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
+    }
+
+    fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+        if self.span == ex.span {
+            self.result = Some(ex);
+        } else {
+            if let hir::ExprKind::Closure(..) = ex.kind
+                && self.include_closures
+                && let closure_header_sp = self.span.with_hi(ex.span.hi())
+                && closure_header_sp == ex.span
+            {
+                self.result = Some(ex);
+            }
+            hir::intravisit::walk_expr(self, ex);
+        }
+    }
+
+    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+        if self.span == ty.span {
+            self.ty_result = Some(ty);
+        } else {
+            hir::intravisit::walk_ty(self, ty);
+        }
+    }
+}
+
+/// Summarizes information
+#[derive(Clone)]
+pub enum ArgKind {
+    /// An argument of non-tuple type. Parameters are (name, ty)
+    Arg(String, String),
+
+    /// An argument of tuple type. For a "found" argument, the span is
+    /// the location in the source of the pattern. For an "expected"
+    /// argument, it will be None. The vector is a list of (name, ty)
+    /// strings for the components of the tuple.
+    Tuple(Option<Span>, Vec<(String, String)>),
+}
+
+impl ArgKind {
+    fn empty() -> ArgKind {
+        ArgKind::Arg("_".to_owned(), "_".to_owned())
+    }
+
+    /// Creates an `ArgKind` from the expected type of an
+    /// argument. It has no name (`_`) and an optional source span.
+    pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
+        match t.kind() {
+            ty::Tuple(tys) => ArgKind::Tuple(
+                span,
+                tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
+            ),
+            _ => ArgKind::Arg("_".to_owned(), t.to_string()),
+        }
+    }
+}
+
+#[derive(Copy, Clone)]
+pub enum DefIdOrName {
+    DefId(DefId),
+    Name(&'static str),
+}
+
+#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)]
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    fn report_fulfillment_errors(
+        &self,
+        mut errors: Vec<FulfillmentError<'tcx>>,
+    ) -> ErrorGuaranteed {
+        self.sub_relations
+            .borrow_mut()
+            .add_constraints(self, errors.iter().map(|e| e.obligation.predicate));
+
+        #[derive(Debug)]
+        struct ErrorDescriptor<'tcx> {
+            predicate: ty::Predicate<'tcx>,
+            index: Option<usize>, // None if this is an old error
+        }
+
+        let mut error_map: FxIndexMap<_, Vec<_>> = self
+            .reported_trait_errors
+            .borrow()
+            .iter()
+            .map(|(&span, predicates)| {
+                (
+                    span,
+                    predicates
+                        .0
+                        .iter()
+                        .map(|&predicate| ErrorDescriptor { predicate, index: None })
+                        .collect(),
+                )
+            })
+            .collect();
+
+        // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics
+        // with more relevant type information and hide redundant E0282 errors.
+        errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() {
+            ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
+                if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) =>
+            {
+                1
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
+            ty::PredicateKind::Coerce(_) => 2,
+            _ => 0,
+        });
+
+        for (index, error) in errors.iter().enumerate() {
+            // We want to ignore desugarings here: spans are equivalent even
+            // if one is the result of a desugaring and the other is not.
+            let mut span = error.obligation.cause.span;
+            let expn_data = span.ctxt().outer_expn_data();
+            if let ExpnKind::Desugaring(_) = expn_data.kind {
+                span = expn_data.call_site;
+            }
+
+            error_map.entry(span).or_default().push(ErrorDescriptor {
+                predicate: error.obligation.predicate,
+                index: Some(index),
+            });
+        }
+
+        // We do this in 2 passes because we want to display errors in order, though
+        // maybe it *is* better to sort errors by span or something.
+        let mut is_suppressed = vec![false; errors.len()];
+        for (_, error_set) in error_map.iter() {
+            // We want to suppress "duplicate" errors with the same span.
+            for error in error_set {
+                if let Some(index) = error.index {
+                    // Suppress errors that are either:
+                    // 1) strictly implied by another error.
+                    // 2) implied by an error with a smaller index.
+                    for error2 in error_set {
+                        if error2.index.is_some_and(|index2| is_suppressed[index2]) {
+                            // Avoid errors being suppressed by already-suppressed
+                            // errors, to prevent all errors from being suppressed
+                            // at once.
+                            continue;
+                        }
+
+                        if self.error_implies(error2.predicate, error.predicate)
+                            && !(error2.index >= error.index
+                                && self.error_implies(error.predicate, error2.predicate))
+                        {
+                            info!("skipping {:?} (implied by {:?})", error, error2);
+                            is_suppressed[index] = true;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        let mut reported = None;
+
+        for from_expansion in [false, true] {
+            for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
+                if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
+                    let guar = self.report_fulfillment_error(error);
+                    self.infcx.set_tainted_by_errors(guar);
+                    reported = Some(guar);
+                    // We want to ignore desugarings here: spans are equivalent even
+                    // if one is the result of a desugaring and the other is not.
+                    let mut span = error.obligation.cause.span;
+                    let expn_data = span.ctxt().outer_expn_data();
+                    if let ExpnKind::Desugaring(_) = expn_data.kind {
+                        span = expn_data.call_site;
+                    }
+                    self.reported_trait_errors
+                        .borrow_mut()
+                        .entry(span)
+                        .or_insert_with(|| (vec![], guar))
+                        .0
+                        .push(error.obligation.predicate);
+                }
+            }
+        }
+
+        // It could be that we don't report an error because we have seen an `ErrorReported` from
+        // another source. We should probably be able to fix most of these, but some are delayed
+        // bugs that get a proper error after this function.
+        reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
+        let mut error = FulfillmentError {
+            obligation: error.obligation.clone(),
+            code: error.code.clone(),
+            root_obligation: error.root_obligation.clone(),
+        };
+        if matches!(
+            error.code,
+            FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
+                | FulfillmentErrorCode::Project(_)
+        ) && self.apply_do_not_recommend(&mut error.obligation)
+        {
+            error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
+        }
+
+        match error.code {
+            FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
+                error.obligation.clone(),
+                &error.root_obligation,
+                selection_error,
+            ),
+            FulfillmentErrorCode::Project(ref e) => {
+                self.report_projection_error(&error.obligation, e)
+            }
+            FulfillmentErrorCode::Ambiguity { overflow: None } => {
+                self.maybe_report_ambiguity(&error.obligation)
+            }
+            FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
+                self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
+            }
+            FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
+                .report_mismatched_types(
+                    &error.obligation.cause,
+                    expected_found.expected,
+                    expected_found.found,
+                    *err,
+                )
+                .emit(),
+            FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
+                let mut diag = self.report_mismatched_consts(
+                    &error.obligation.cause,
+                    expected_found.expected,
+                    expected_found.found,
+                    *err,
+                );
+                let code = error.obligation.cause.code().peel_derives().peel_match_impls();
+                if let ObligationCauseCode::WhereClause(..)
+                | ObligationCauseCode::WhereClauseInExpr(..) = code
+                {
+                    self.note_obligation_cause_code(
+                        error.obligation.cause.body_id,
+                        &mut diag,
+                        error.obligation.predicate,
+                        error.obligation.param_env,
+                        code,
+                        &mut vec![],
+                        &mut Default::default(),
+                    );
+                }
+                diag.emit()
+            }
+            FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
+        }
+    }
+}
+
+/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
+/// string.
+pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
+    use std::fmt::Write;
+
+    let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity();
+    let mut w = "impl".to_owned();
+
+    let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
+
+    // FIXME: Currently only handles ?Sized.
+    //        Needs to support ?Move and ?DynSized when they are implemented.
+    let mut types_without_default_bounds = FxIndexSet::default();
+    let sized_trait = tcx.lang_items().sized_trait();
+
+    let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
+    if !arg_names.is_empty() {
+        types_without_default_bounds.extend(args.types());
+        w.push('<');
+        w.push_str(&arg_names.join(", "));
+        w.push('>');
+    }
+
+    write!(
+        w,
+        " {} for {}",
+        trait_ref.print_only_trait_path(),
+        tcx.type_of(impl_def_id).instantiate_identity()
+    )
+    .unwrap();
+
+    // The predicates will contain default bounds like `T: Sized`. We need to
+    // remove these bounds, and add `T: ?Sized` to any untouched type parameters.
+    let predicates = tcx.predicates_of(impl_def_id).predicates;
+    let mut pretty_predicates =
+        Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
+
+    for (p, _) in predicates {
+        if let Some(poly_trait_ref) = p.as_trait_clause() {
+            if Some(poly_trait_ref.def_id()) == sized_trait {
+                // FIXME(#120456) - is `swap_remove` correct?
+                types_without_default_bounds.swap_remove(&poly_trait_ref.self_ty().skip_binder());
+                continue;
+            }
+        }
+        pretty_predicates.push(p.to_string());
+    }
+
+    pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized")));
+
+    if !pretty_predicates.is_empty() {
+        write!(w, "\n  where {}", pretty_predicates.join(", ")).unwrap();
+    }
+
+    w.push(';');
+    Some(w)
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 32c8a454b40..e90fe8fb94d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -1,5 +1,10 @@
 use super::{ObligationCauseCode, PredicateObligation};
+use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt;
+use crate::errors::{
+    EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
+};
 use crate::infer::error_reporting::TypeErrCtxt;
+use crate::infer::InferCtxtExt;
 use rustc_ast::AttrArgs;
 use rustc_ast::AttrArgsEq;
 use rustc_ast::AttrKind;
@@ -21,12 +26,6 @@ use rustc_span::Span;
 use std::iter;
 use std::path::PathBuf;
 
-use crate::errors::{
-    EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
-};
-
-use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
-
 /// The symbols which are always allowed in a format string
 static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
     kw::SelfUpper,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
new file mode 100644
index 00000000000..061a5a4be20
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
@@ -0,0 +1,197 @@
+use std::fmt;
+
+use rustc_errors::{
+    struct_span_code_err, Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, E0275,
+};
+use rustc_hir::def::Namespace;
+use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_infer::infer::error_reporting::TypeErrCtxt;
+use rustc_infer::traits::{Obligation, PredicateObligation};
+use rustc_macros::extension;
+use rustc_middle::ty::print::{FmtPrinter, Print};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_session::Limit;
+use rustc_span::Span;
+use rustc_type_ir::Upcast;
+
+use super::InferCtxtPrivExt;
+use crate::error_reporting::traits::suggestions::TypeErrCtxtExt;
+
+pub enum OverflowCause<'tcx> {
+    DeeplyNormalize(ty::AliasTerm<'tcx>),
+    TraitSolver(ty::Predicate<'tcx>),
+}
+
+pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
+    tcx: TyCtxt<'tcx>,
+    err: &mut Diag<'_, G>,
+) {
+    let suggested_limit = match tcx.recursion_limit() {
+        Limit(0) => Limit(2),
+        limit => limit * 2,
+    };
+    err.help(format!(
+        "consider increasing the recursion limit by adding a \
+         `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
+        suggested_limit,
+        tcx.crate_name(LOCAL_CRATE),
+    ));
+}
+
+#[extension(pub trait TypeErrCtxtOverflowExt<'a, 'tcx>)]
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    /// Reports that an overflow has occurred and halts compilation. We
+    /// halt compilation unconditionally because it is important that
+    /// overflows never be masked -- they basically represent computations
+    /// whose result could not be truly determined and thus we can't say
+    /// if the program type checks or not -- and they are unusual
+    /// occurrences in any case.
+    fn report_overflow_error(
+        &self,
+        cause: OverflowCause<'tcx>,
+        span: Span,
+        suggest_increasing_limit: bool,
+        mutate: impl FnOnce(&mut Diag<'_>),
+    ) -> ! {
+        let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
+        mutate(&mut err);
+        err.emit();
+        FatalError.raise();
+    }
+
+    fn build_overflow_error(
+        &self,
+        cause: OverflowCause<'tcx>,
+        span: Span,
+        suggest_increasing_limit: bool,
+    ) -> Diag<'a> {
+        fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
+        where
+            T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
+        {
+            let s = value.to_string();
+            if s.len() > 50 {
+                // We don't need to save the type to a file, we will be talking about this type already
+                // in a separate note when we explain the obligation, so it will be available that way.
+                let mut cx: FmtPrinter<'_, '_> =
+                    FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6));
+                value.print(&mut cx).unwrap();
+                cx.into_buffer()
+            } else {
+                s
+            }
+        }
+
+        let mut err = match cause {
+            OverflowCause::DeeplyNormalize(alias_term) => {
+                let alias_term = self.resolve_vars_if_possible(alias_term);
+                let kind = alias_term.kind(self.tcx).descr();
+                let alias_str = with_short_path(self.tcx, alias_term);
+                struct_span_code_err!(
+                    self.dcx(),
+                    span,
+                    E0275,
+                    "overflow normalizing the {kind} `{alias_str}`",
+                )
+            }
+            OverflowCause::TraitSolver(predicate) => {
+                let predicate = self.resolve_vars_if_possible(predicate);
+                match predicate.kind().skip_binder() {
+                    ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ })
+                    | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
+                        struct_span_code_err!(
+                            self.dcx(),
+                            span,
+                            E0275,
+                            "overflow assigning `{a}` to `{b}`",
+                        )
+                    }
+                    _ => {
+                        let pred_str = with_short_path(self.tcx, predicate);
+                        struct_span_code_err!(
+                            self.dcx(),
+                            span,
+                            E0275,
+                            "overflow evaluating the requirement `{pred_str}`",
+                        )
+                    }
+                }
+            }
+        };
+
+        if suggest_increasing_limit {
+            suggest_new_overflow_limit(self.tcx, &mut err);
+        }
+
+        err
+    }
+
+    /// Reports that an overflow has occurred and halts compilation. We
+    /// halt compilation unconditionally because it is important that
+    /// overflows never be masked -- they basically represent computations
+    /// whose result could not be truly determined and thus we can't say
+    /// if the program type checks or not -- and they are unusual
+    /// occurrences in any case.
+    fn report_overflow_obligation<T>(
+        &self,
+        obligation: &Obligation<'tcx, T>,
+        suggest_increasing_limit: bool,
+    ) -> !
+    where
+        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
+    {
+        let predicate = obligation.predicate.clone().upcast(self.tcx);
+        let predicate = self.resolve_vars_if_possible(predicate);
+        self.report_overflow_error(
+            OverflowCause::TraitSolver(predicate),
+            obligation.cause.span,
+            suggest_increasing_limit,
+            |err| {
+                self.note_obligation_cause_code(
+                    obligation.cause.body_id,
+                    err,
+                    predicate,
+                    obligation.param_env,
+                    obligation.cause.code(),
+                    &mut vec![],
+                    &mut Default::default(),
+                );
+            },
+        );
+    }
+
+    /// Reports that a cycle was detected which led to overflow and halts
+    /// compilation. This is equivalent to `report_overflow_obligation` except
+    /// that we can give a more helpful error message (and, in particular,
+    /// we do not suggest increasing the overflow limit, which is not
+    /// going to help).
+    fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
+        let cycle = self.resolve_vars_if_possible(cycle.to_owned());
+        assert!(!cycle.is_empty());
+
+        debug!(?cycle, "report_overflow_error_cycle");
+
+        // The 'deepest' obligation is most likely to have a useful
+        // cause 'backtrace'
+        self.report_overflow_obligation(
+            cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
+            false,
+        );
+    }
+
+    fn report_overflow_no_abort(
+        &self,
+        obligation: PredicateObligation<'tcx>,
+        suggest_increasing_limit: bool,
+    ) -> ErrorGuaranteed {
+        let obligation = self.resolve_vars_if_possible(obligation);
+        let mut err = self.build_overflow_error(
+            OverflowCause::TraitSolver(obligation.predicate),
+            obligation.cause.span,
+            suggest_increasing_limit,
+        );
+        self.note_obligation_cause(&mut err, &obligation);
+        self.point_at_returns_when_relevant(&mut err, &obligation);
+        err.emit()
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index ccf86dbb1d0..2cf808f962f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -44,8 +44,8 @@ use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::iter;
 
+use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt;
 use crate::infer::InferCtxtExt as _;
-use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_middle::ty::print::{
     with_forced_trimmed_paths, with_no_trimmed_paths, PrintPolyTraitPredicateExt as _,
@@ -3472,6 +3472,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     )
                 });
             }
+            // Suppress `compare_type_predicate_entailment` errors for RPITITs, since they
+            // should be implied by the parent method.
+            ObligationCauseCode::CompareImplItem { trait_item_def_id, .. }
+                if tcx.is_impl_trait_in_trait(trait_item_def_id) => {}
             ObligationCauseCode::CompareImplItem { trait_item_def_id, kind, .. } => {
                 let item_name = tcx.item_name(trait_item_def_id);
                 let msg = format!(
@@ -4114,7 +4118,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     expr = binding_expr;
                 }
                 if let hir::Node::Param(param) = parent {
-                    // ...and it is a an fn argument.
+                    // ...and it is an fn argument.
                     let prev_ty = self.resolve_vars_if_possible(
                         typeck_results
                             .node_type_opt(param.hir_id)
@@ -4619,6 +4623,132 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             );
         }
     }
+
+    #[instrument(level = "debug", skip_all)]
+    fn suggest_unsized_bound_if_applicable(
+        &self,
+        err: &mut Diag<'_>,
+        obligation: &PredicateObligation<'tcx>,
+    ) {
+        let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
+            obligation.predicate.kind().skip_binder()
+        else {
+            return;
+        };
+        let (ObligationCauseCode::WhereClause(item_def_id, span)
+        | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) =
+            *obligation.cause.code().peel_derives()
+        else {
+            return;
+        };
+        if span.is_dummy() {
+            return;
+        }
+        debug!(?pred, ?item_def_id, ?span);
+
+        let (Some(node), true) = (
+            self.tcx.hir().get_if_local(item_def_id),
+            self.tcx.is_lang_item(pred.def_id(), LangItem::Sized),
+        ) else {
+            return;
+        };
+
+        let Some(generics) = node.generics() else {
+            return;
+        };
+        let sized_trait = self.tcx.lang_items().sized_trait();
+        debug!(?generics.params);
+        debug!(?generics.predicates);
+        let Some(param) = generics.params.iter().find(|param| param.span == span) else {
+            return;
+        };
+        // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
+        // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
+        let explicitly_sized = generics
+            .bounds_for_param(param.def_id)
+            .flat_map(|bp| bp.bounds)
+            .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
+        if explicitly_sized {
+            return;
+        }
+        debug!(?param);
+        match node {
+            hir::Node::Item(
+                item @ hir::Item {
+                    // Only suggest indirection for uses of type parameters in ADTs.
+                    kind:
+                        hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
+                    ..
+                },
+            ) => {
+                if self.suggest_indirection_for_unsized(err, item, param) {
+                    return;
+                }
+            }
+            _ => {}
+        };
+
+        // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
+        let (span, separator, open_paren_sp) =
+            if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
+                (s, " +", open_paren_sp)
+            } else {
+                (param.name.ident().span.shrink_to_hi(), ":", None)
+            };
+
+        let mut suggs = vec![];
+        let suggestion = format!("{separator} ?Sized");
+
+        if let Some(open_paren_sp) = open_paren_sp {
+            suggs.push((open_paren_sp, "(".to_string()));
+            suggs.push((span, format!("){suggestion}")));
+        } else {
+            suggs.push((span, suggestion));
+        }
+
+        err.multipart_suggestion_verbose(
+            "consider relaxing the implicit `Sized` restriction",
+            suggs,
+            Applicability::MachineApplicable,
+        );
+    }
+
+    fn suggest_indirection_for_unsized(
+        &self,
+        err: &mut Diag<'_>,
+        item: &hir::Item<'tcx>,
+        param: &hir::GenericParam<'tcx>,
+    ) -> bool {
+        // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
+        // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
+        // is not. Look for invalid "bare" parameter uses, and suggest using indirection.
+        let mut visitor =
+            FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
+        visitor.visit_item(item);
+        if visitor.invalid_spans.is_empty() {
+            return false;
+        }
+        let mut multispan: MultiSpan = param.span.into();
+        multispan.push_span_label(
+            param.span,
+            format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
+        );
+        for sp in visitor.invalid_spans {
+            multispan.push_span_label(
+                sp,
+                format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
+            );
+        }
+        err.span_help(
+            multispan,
+            format!(
+                "you could relax the implicit `Sized` bound on `{T}` if it were \
+                used through indirection like `&{T}` or `Box<{T}>`",
+                T = param.name.ident(),
+            ),
+        );
+        true
+    }
 }
 
 /// Add a hint to add a missing borrow or remove an unnecessary one.
@@ -5122,3 +5252,46 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
 
     (ty, refs)
 }
+
+/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
+/// `param: ?Sized` would be a valid constraint.
+struct FindTypeParam {
+    param: rustc_span::Symbol,
+    invalid_spans: Vec<Span>,
+    nested: bool,
+}
+
+impl<'v> Visitor<'v> for FindTypeParam {
+    fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
+        // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
+    }
+
+    fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
+        // We collect the spans of all uses of the "bare" type param, like in `field: T` or
+        // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
+        // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
+        // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
+        // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
+        // in that case should make what happened clear enough.
+        match ty.kind {
+            hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
+            hir::TyKind::Path(hir::QPath::Resolved(None, path))
+                if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
+            {
+                if !self.nested {
+                    debug!(?ty, "FindTypeParam::visit_ty");
+                    self.invalid_spans.push(ty.span);
+                }
+            }
+            hir::TyKind::Path(_) => {
+                let prev = self.nested;
+                self.nested = true;
+                hir::intravisit::walk_ty(self, ty);
+                self.nested = prev;
+            }
+            _ => {
+                hir::intravisit::walk_ty(self, ty);
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index c95649e2ffb..ad087620ae0 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -1,3 +1,4 @@
+use crate::infer::at::ToTrace;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt, SelectionContext};
 
@@ -17,6 +18,16 @@ pub use rustc_infer::infer::*;
 
 #[extension(pub trait InferCtxtExt<'tcx>)]
 impl<'tcx> InferCtxt<'tcx> {
+    fn can_eq<T: ToTrace<'tcx>>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool {
+        self.probe(|_| {
+            let ocx = ObligationCtxt::new(self);
+            let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, a, b) else {
+                return false;
+            };
+            ocx.select_where_possible().is_empty()
+        })
+    }
+
     fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
         let ty = self.resolve_vars_if_possible(ty);
 
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 50c618bb3bd..d0a12d73941 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -26,12 +26,14 @@
 #![feature(never_type)]
 #![feature(rustdoc_internals)]
 #![feature(type_alias_impl_trait)]
+#![feature(unwrap_infallible)]
 #![recursion_limit = "512"] // For rustdoc
 // tidy-alphabetical-end
 
 #[macro_use]
 extern crate tracing;
 
+pub mod error_reporting;
 pub mod errors;
 pub mod infer;
 pub mod regions;
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 643d5f80480..f67518a577e 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -1,24 +1,19 @@
 use std::ops::Deref;
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalExt as _, CanonicalVarInfo, CanonicalVarValues,
 };
-use rustc_infer::infer::{
-    BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt,
-};
+use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::solve::Goal;
-use rustc_infer::traits::util::supertraits;
 use rustc_infer::traits::{ObligationCause, Reveal};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
 use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
-use rustc_type_ir::relate::Relate;
 use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode};
 
-use crate::traits::coherence::trait_ref_is_knowable;
 use crate::traits::specialization_graph;
 
 #[repr(transparent)]
@@ -48,13 +43,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
 
     type Span = Span;
 
-    fn solver_mode(&self) -> ty::solve::SolverMode {
-        match self.intercrate {
-            true => SolverMode::Coherence,
-            false => SolverMode::Normal,
-        }
-    }
-
     fn build_with_canonical<V>(
         interner: TyCtxt<'tcx>,
         solver_mode: SolverMode,
@@ -74,104 +62,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         (SolverDelegate(infcx), value, vars)
     }
 
-    fn universe(&self) -> ty::UniverseIndex {
-        self.0.universe()
-    }
-
-    fn create_next_universe(&self) -> ty::UniverseIndex {
-        self.0.create_next_universe()
-    }
-
-    fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> {
-        // FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
-        // ty infers will give you the universe of the var it resolved to not the universe
-        // it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
-        // try to print out `?0.1` it will just print `?0`.
-        match self.0.probe_ty_var(vid) {
-            Err(universe) => Some(universe),
-            Ok(_) => None,
-        }
-    }
-
-    fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
-        match self.0.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
-            Err(universe) => Some(universe),
-            Ok(_) => None,
-        }
-    }
-
-    fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> {
-        // Same issue as with `universe_of_ty`
-        match self.0.probe_const_var(ct) {
-            Err(universe) => Some(universe),
-            Ok(_) => None,
-        }
-    }
-
-    fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
-        self.0.root_var(var)
-    }
-
-    fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
-        self.0.root_const_var(var)
-    }
-
-    fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> {
-        match self.0.probe_ty_var(vid) {
-            Ok(ty) => ty,
-            Err(_) => Ty::new_var(self.0.tcx, self.0.root_var(vid)),
-        }
-    }
-
-    fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
-        self.0.opportunistic_resolve_int_var(vid)
-    }
-
-    fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
-        self.0.opportunistic_resolve_float_var(vid)
-    }
-
-    fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> {
-        match self.0.probe_const_var(vid) {
-            Ok(ct) => ct,
-            Err(_) => ty::Const::new_var(self.0.tcx, self.0.root_const_var(vid)),
-        }
-    }
-
-    fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> {
-        match self.0.probe_effect_var(vid) {
-            Some(ct) => ct,
-            None => ty::Const::new_infer(
-                self.0.tcx,
-                ty::InferConst::EffectVar(self.0.root_effect_var(vid)),
-            ),
-        }
-    }
-
-    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
-        self.0
-            .inner
-            .borrow_mut()
-            .unwrap_region_constraints()
-            .opportunistic_resolve_var(self.0.tcx, vid)
-    }
-
-    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
-        self.0.defining_opaque_types()
-    }
-
-    fn next_ty_infer(&self) -> Ty<'tcx> {
-        self.0.next_ty_var(DUMMY_SP)
-    }
-
-    fn next_const_infer(&self) -> ty::Const<'tcx> {
-        self.0.next_const_var(DUMMY_SP)
-    }
-
-    fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
-        self.0.fresh_args_for_item(DUMMY_SP, def_id)
-    }
-
     fn fresh_var_for_kind_with_span(
         &self,
         arg: ty::GenericArg<'tcx>,
@@ -186,68 +76,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         }
     }
 
-    fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
-        &self,
-        value: ty::Binder<'tcx, T>,
-    ) -> T {
-        self.0.instantiate_binder_with_fresh_vars(
-            DUMMY_SP,
-            BoundRegionConversionTime::HigherRankedType,
-            value,
-        )
-    }
-
-    fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
-        &self,
-        value: ty::Binder<'tcx, T>,
-        f: impl FnOnce(T) -> U,
-    ) -> U {
-        self.0.enter_forall(value, f)
-    }
-
-    fn relate<T: Relate<TyCtxt<'tcx>>>(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        lhs: T,
-        variance: ty::Variance,
-        rhs: T,
-    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
-        self.0.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
-    }
-
-    fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        lhs: T,
-        rhs: T,
-    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
-        self.0
-            .at(&ObligationCause::dummy(), param_env)
-            .eq_structurally_relating_aliases_no_trace(lhs, rhs)
-    }
-
-    fn resolve_vars_if_possible<T>(&self, value: T) -> T
-    where
-        T: TypeFoldable<TyCtxt<'tcx>>,
-    {
-        self.0.resolve_vars_if_possible(value)
-    }
-
-    fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
-        self.0.probe(|_| probe())
-    }
-
     fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> {
         self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
     }
 
-    fn elaborate_supertraits(
-        interner: TyCtxt<'tcx>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-    ) -> impl Iterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>> {
-        supertraits(interner, trait_ref)
-    }
-
     fn try_const_eval_resolve(
         &self,
         param_env: ty::ParamEnv<'tcx>,
@@ -265,14 +97,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         }
     }
 
-    fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
-        self.0.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup)
-    }
-
-    fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
-        self.0.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy());
-    }
-
     fn well_formed_goals(
         &self,
         param_env: ty::ParamEnv<'tcx>,
@@ -367,15 +191,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         let _ = self.take_opaque_types();
     }
 
-    fn trait_ref_is_knowable<E: std::fmt::Debug>(
-        &self,
-        trait_ref: ty::TraitRef<'tcx>,
-        lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
-    ) -> Result<bool, E> {
-        trait_ref_is_knowable(&self.0, trait_ref, lazily_normalize_ty)
-            .map(|is_knowable| is_knowable.is_ok())
-    }
-
     fn fetch_eligible_assoc_item(
         &self,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index 2679da942b7..ca313590265 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -1,7 +1,7 @@
 use std::fmt::Debug;
 use std::marker::PhantomData;
 
-use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt};
+use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtOverflowExt};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
 use rustc_data_structures::stack::ensure_sufficient_stack;
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index a4177d8a93f..7e996c5c5ef 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -25,41 +25,13 @@ use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
+pub use rustc_next_trait_solver::coherence::*;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
 use std::fmt::Debug;
-use std::ops::ControlFlow;
 
-use super::error_reporting::suggest_new_overflow_limit;
 use super::ObligationCtxt;
-
-/// Whether we do the orphan check relative to this crate or to some remote crate.
-#[derive(Copy, Clone, Debug)]
-pub enum InCrate {
-    Local { mode: OrphanCheckMode },
-    Remote,
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum OrphanCheckMode {
-    /// Proper orphan check.
-    Proper,
-    /// Improper orphan check for backward compatibility.
-    ///
-    /// In this mode, type params inside projections are considered to be covered
-    /// even if the projection may normalize to a type that doesn't actually cover
-    /// them. This is unsound. See also [#124559] and [#99554].
-    ///
-    /// [#124559]: https://github.com/rust-lang/rust/issues/124559
-    /// [#99554]: https://github.com/rust-lang/rust/issues/99554
-    Compat,
-}
-
-#[derive(Debug, Copy, Clone)]
-pub enum Conflict {
-    Upstream,
-    Downstream,
-}
+use crate::error_reporting::traits::suggest_new_overflow_limit;
 
 pub struct OverlapResult<'tcx> {
     pub impl_header: ty::ImplHeader<'tcx>,
@@ -121,7 +93,7 @@ pub fn overlapping_impls(
     // Before doing expensive operations like entering an inference context, do
     // a quick check via fast_reject to tell if the impl headers could possibly
     // unify.
-    let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey };
+    let drcx = DeepRejectCtxt::new(tcx, TreatParams::AsCandidateKey);
     let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
     let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
     let may_overlap = match (impl1_ref, impl2_ref) {
@@ -612,426 +584,6 @@ fn try_prove_negated_where_clause<'tcx>(
     true
 }
 
-/// Returns whether all impls which would apply to the `trait_ref`
-/// e.g. `Ty: Trait<Arg>` are already known in the local crate.
-///
-/// This both checks whether any downstream or sibling crates could
-/// implement it and whether an upstream crate can add this impl
-/// without breaking backwards compatibility.
-#[instrument(level = "debug", skip(infcx, lazily_normalize_ty), ret)]
-pub fn trait_ref_is_knowable<'tcx, E: Debug>(
-    infcx: &InferCtxt<'tcx>,
-    trait_ref: ty::TraitRef<'tcx>,
-    mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
-) -> Result<Result<(), Conflict>, E> {
-    if orphan_check_trait_ref(infcx, trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok()
-    {
-        // A downstream or cousin crate is allowed to implement some
-        // generic parameters of this trait-ref.
-        return Ok(Err(Conflict::Downstream));
-    }
-
-    if trait_ref_is_local_or_fundamental(infcx.tcx, trait_ref) {
-        // This is a local or fundamental trait, so future-compatibility
-        // is no concern. We know that downstream/cousin crates are not
-        // allowed to implement a generic parameter of this trait ref,
-        // which means impls could only come from dependencies of this
-        // crate, which we already know about.
-        return Ok(Ok(()));
-    }
-
-    // This is a remote non-fundamental trait, so if another crate
-    // can be the "final owner" of the generic parameters of this trait-ref,
-    // they are allowed to implement it future-compatibly.
-    //
-    // However, if we are a final owner, then nobody else can be,
-    // and if we are an intermediate owner, then we don't care
-    // about future-compatibility, which means that we're OK if
-    // we are an owner.
-    if orphan_check_trait_ref(
-        infcx,
-        trait_ref,
-        InCrate::Local { mode: OrphanCheckMode::Proper },
-        &mut lazily_normalize_ty,
-    )?
-    .is_ok()
-    {
-        Ok(Ok(()))
-    } else {
-        Ok(Err(Conflict::Upstream))
-    }
-}
-
-pub fn trait_ref_is_local_or_fundamental<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_ref: ty::TraitRef<'tcx>,
-) -> bool {
-    trait_ref.def_id.is_local() || tcx.has_attr(trait_ref.def_id, sym::fundamental)
-}
-
-#[derive(Debug, Copy, Clone)]
-pub enum IsFirstInputType {
-    No,
-    Yes,
-}
-
-impl From<bool> for IsFirstInputType {
-    fn from(b: bool) -> IsFirstInputType {
-        match b {
-            false => IsFirstInputType::No,
-            true => IsFirstInputType::Yes,
-        }
-    }
-}
-
-#[derive(Debug)]
-pub enum OrphanCheckErr<'tcx, T> {
-    NonLocalInputType(Vec<(Ty<'tcx>, IsFirstInputType)>),
-    UncoveredTyParams(UncoveredTyParams<'tcx, T>),
-}
-
-#[derive(Debug)]
-pub struct UncoveredTyParams<'tcx, T> {
-    pub uncovered: T,
-    pub local_ty: Option<Ty<'tcx>>,
-}
-
-/// Checks whether a trait-ref is potentially implementable by a crate.
-///
-/// The current rule is that a trait-ref orphan checks in a crate C:
-///
-/// 1. Order the parameters in the trait-ref in generic parameters order
-/// - Self first, others linearly (e.g., `<U as Foo<V, W>>` is U < V < W).
-/// 2. Of these type parameters, there is at least one type parameter
-///    in which, walking the type as a tree, you can reach a type local
-///    to C where all types in-between are fundamental types. Call the
-///    first such parameter the "local key parameter".
-///     - e.g., `Box<LocalType>` is OK, because you can visit LocalType
-///       going through `Box`, which is fundamental.
-///     - similarly, `FundamentalPair<Vec<()>, Box<LocalType>>` is OK for
-///       the same reason.
-///     - but (knowing that `Vec<T>` is non-fundamental, and assuming it's
-///       not local), `Vec<LocalType>` is bad, because `Vec<->` is between
-///       the local type and the type parameter.
-/// 3. Before this local type, no generic type parameter of the impl must
-///    be reachable through fundamental types.
-///     - e.g. `impl<T> Trait<LocalType> for Vec<T>` is fine, as `Vec` is not fundamental.
-///     - while `impl<T> Trait<LocalType> for Box<T>` results in an error, as `T` is
-///       reachable through the fundamental type `Box`.
-/// 4. Every type in the local key parameter not known in C, going
-///    through the parameter's type tree, must appear only as a subtree of
-///    a type local to C, with only fundamental types between the type
-///    local to C and the local key parameter.
-///     - e.g., `Vec<LocalType<T>>>` (or equivalently `Box<Vec<LocalType<T>>>`)
-///     is bad, because the only local type with `T` as a subtree is
-///     `LocalType<T>`, and `Vec<->` is between it and the type parameter.
-///     - similarly, `FundamentalPair<LocalType<T>, T>` is bad, because
-///     the second occurrence of `T` is not a subtree of *any* local type.
-///     - however, `LocalType<Vec<T>>` is OK, because `T` is a subtree of
-///     `LocalType<Vec<T>>`, which is local and has no types between it and
-///     the type parameter.
-///
-/// The orphan rules actually serve several different purposes:
-///
-/// 1. They enable link-safety - i.e., 2 mutually-unknowing crates (where
-///    every type local to one crate is unknown in the other) can't implement
-///    the same trait-ref. This follows because it can be seen that no such
-///    type can orphan-check in 2 such crates.
-///
-///    To check that a local impl follows the orphan rules, we check it in
-///    InCrate::Local mode, using type parameters for the "generic" types.
-///
-///    In InCrate::Local mode the orphan check succeeds if the current crate
-///    is definitely allowed to implement the given trait (no false positives).
-///
-/// 2. They ground negative reasoning for coherence. If a user wants to
-///    write both a conditional blanket impl and a specific impl, we need to
-///    make sure they do not overlap. For example, if we write
-///    ```ignore (illustrative)
-///    impl<T> IntoIterator for Vec<T>
-///    impl<T: Iterator> IntoIterator for T
-///    ```
-///    We need to be able to prove that `Vec<$0>: !Iterator` for every type $0.
-///    We can observe that this holds in the current crate, but we need to make
-///    sure this will also hold in all unknown crates (both "independent" crates,
-///    which we need for link-safety, and also child crates, because we don't want
-///    child crates to get error for impl conflicts in a *dependency*).
-///
-///    For that, we only allow negative reasoning if, for every assignment to the
-///    inference variables, every unknown crate would get an orphan error if they
-///    try to implement this trait-ref. To check for this, we use InCrate::Remote
-///    mode. That is sound because we already know all the impls from known crates.
-///
-///    In InCrate::Remote mode the orphan check succeeds if a foreign crate
-///    *could* implement the given trait (no false negatives).
-///
-/// 3. For non-`#[fundamental]` traits, they guarantee that parent crates can
-///    add "non-blanket" impls without breaking negative reasoning in dependent
-///    crates. This is the "rebalancing coherence" (RFC 1023) restriction.
-///
-///    For that, we only allow a crate to perform negative reasoning on
-///    non-local-non-`#[fundamental]` if there's a local key parameter as per (2).
-///
-///    Because we never perform negative reasoning generically (coherence does
-///    not involve type parameters), this can be interpreted as doing the full
-///    orphan check (using InCrate::Local mode), instantiating non-local known
-///    types for all inference variables.
-///
-///    This allows for crates to future-compatibly add impls as long as they
-///    can't apply to types with a key parameter in a child crate - applying
-///    the rules, this basically means that every type parameter in the impl
-///    must appear behind a non-fundamental type (because this is not a
-///    type-system requirement, crate owners might also go for "semantic
-///    future-compatibility" involving things such as sealed traits, but
-///    the above requirement is sufficient, and is necessary in "open world"
-///    cases).
-///
-/// Note that this function is never called for types that have both type
-/// parameters and inference variables.
-#[instrument(level = "trace", skip(infcx, lazily_normalize_ty), ret)]
-pub fn orphan_check_trait_ref<'tcx, E: Debug>(
-    infcx: &InferCtxt<'tcx>,
-    trait_ref: ty::TraitRef<'tcx>,
-    in_crate: InCrate,
-    lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
-) -> Result<Result<(), OrphanCheckErr<'tcx, Ty<'tcx>>>, E> {
-    if trait_ref.has_param() {
-        bug!("orphan check only expects inference variables: {trait_ref:?}");
-    }
-
-    let mut checker = OrphanChecker::new(infcx, in_crate, lazily_normalize_ty);
-    Ok(match trait_ref.visit_with(&mut checker) {
-        ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
-        ControlFlow::Break(residual) => match residual {
-            OrphanCheckEarlyExit::NormalizationFailure(err) => return Err(err),
-            OrphanCheckEarlyExit::UncoveredTyParam(ty) => {
-                // Does there exist some local type after the `ParamTy`.
-                checker.search_first_local_ty = true;
-                let local_ty = match trait_ref.visit_with(&mut checker).break_value() {
-                    Some(OrphanCheckEarlyExit::LocalTy(local_ty)) => Some(local_ty),
-                    _ => None,
-                };
-                Err(OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
-                    uncovered: ty,
-                    local_ty,
-                }))
-            }
-            OrphanCheckEarlyExit::LocalTy(_) => Ok(()),
-        },
-    })
-}
-
-struct OrphanChecker<'a, 'tcx, F> {
-    infcx: &'a InferCtxt<'tcx>,
-    in_crate: InCrate,
-    in_self_ty: bool,
-    lazily_normalize_ty: F,
-    /// Ignore orphan check failures and exclusively search for the first local type.
-    search_first_local_ty: bool,
-    non_local_tys: Vec<(Ty<'tcx>, IsFirstInputType)>,
-}
-
-impl<'a, 'tcx, F, E> OrphanChecker<'a, 'tcx, F>
-where
-    F: FnOnce(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
-{
-    fn new(infcx: &'a InferCtxt<'tcx>, in_crate: InCrate, lazily_normalize_ty: F) -> Self {
-        OrphanChecker {
-            infcx,
-            in_crate,
-            in_self_ty: true,
-            lazily_normalize_ty,
-            search_first_local_ty: false,
-            non_local_tys: Vec::new(),
-        }
-    }
-
-    fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> {
-        self.non_local_tys.push((t, self.in_self_ty.into()));
-        ControlFlow::Continue(())
-    }
-
-    fn found_uncovered_ty_param(
-        &mut self,
-        ty: Ty<'tcx>,
-    ) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> {
-        if self.search_first_local_ty {
-            return ControlFlow::Continue(());
-        }
-
-        ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty))
-    }
-
-    fn def_id_is_local(&mut self, def_id: DefId) -> bool {
-        match self.in_crate {
-            InCrate::Local { .. } => def_id.is_local(),
-            InCrate::Remote => false,
-        }
-    }
-}
-
-enum OrphanCheckEarlyExit<'tcx, E> {
-    NormalizationFailure(E),
-    UncoveredTyParam(Ty<'tcx>),
-    LocalTy(Ty<'tcx>),
-}
-
-impl<'a, 'tcx, F, E> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'a, 'tcx, F>
-where
-    F: FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
-{
-    type Result = ControlFlow<OrphanCheckEarlyExit<'tcx, E>>;
-
-    fn visit_region(&mut self, _r: ty::Region<'tcx>) -> Self::Result {
-        ControlFlow::Continue(())
-    }
-
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
-        let ty = self.infcx.shallow_resolve(ty);
-        let ty = match (self.lazily_normalize_ty)(ty) {
-            Ok(norm_ty) if norm_ty.is_ty_var() => ty,
-            Ok(norm_ty) => norm_ty,
-            Err(err) => return ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)),
-        };
-
-        let result = match *ty.kind() {
-            ty::Bool
-            | ty::Char
-            | ty::Int(..)
-            | ty::Uint(..)
-            | ty::Float(..)
-            | ty::Str
-            | ty::FnDef(..)
-            | ty::Pat(..)
-            | ty::FnPtr(_)
-            | ty::Array(..)
-            | ty::Slice(..)
-            | ty::RawPtr(..)
-            | ty::Never
-            | ty::Tuple(..) => self.found_non_local_ty(ty),
-
-            ty::Param(..) => bug!("unexpected ty param"),
-
-            ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => {
-                match self.in_crate {
-                    InCrate::Local { .. } => self.found_uncovered_ty_param(ty),
-                    // The inference variable might be unified with a local
-                    // type in that remote crate.
-                    InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
-                }
-            }
-
-            // A rigid alias may normalize to anything.
-            // * If it references an infer var, placeholder or bound ty, it may
-            //   normalize to that, so we have to treat it as an uncovered ty param.
-            // * Otherwise it may normalize to any non-type-generic type
-            //   be it local or non-local.
-            ty::Alias(kind, _) => {
-                if ty.has_type_flags(
-                    ty::TypeFlags::HAS_TY_PLACEHOLDER
-                        | ty::TypeFlags::HAS_TY_BOUND
-                        | ty::TypeFlags::HAS_TY_INFER,
-                ) {
-                    match self.in_crate {
-                        InCrate::Local { mode } => match kind {
-                            ty::Projection if let OrphanCheckMode::Compat = mode => {
-                                ControlFlow::Continue(())
-                            }
-                            _ => self.found_uncovered_ty_param(ty),
-                        },
-                        InCrate::Remote => {
-                            // The inference variable might be unified with a local
-                            // type in that remote crate.
-                            ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
-                        }
-                    }
-                } else {
-                    // Regarding *opaque types* specifically, we choose to treat them as non-local,
-                    // even those that appear within the same crate. This seems somewhat surprising
-                    // at first, but makes sense when you consider that opaque types are supposed
-                    // to hide the underlying type *within the same crate*. When an opaque type is
-                    // used from outside the module where it is declared, it should be impossible to
-                    // observe anything about it other than the traits that it implements.
-                    //
-                    // The alternative would be to look at the underlying type to determine whether
-                    // or not the opaque type itself should be considered local.
-                    //
-                    // However, this could make it a breaking change to switch the underlying hidden
-                    // type from a local type to a remote type. This would violate the rule that
-                    // opaque types should be completely opaque apart from the traits that they
-                    // implement, so we don't use this behavior.
-                    // Addendum: Moreover, revealing the underlying type is likely to cause cycle
-                    // errors as we rely on coherence / the specialization graph during typeck.
-
-                    self.found_non_local_ty(ty)
-                }
-            }
-
-            // For fundamental types, we just look inside of them.
-            ty::Ref(_, ty, _) => ty.visit_with(self),
-            ty::Adt(def, args) => {
-                if self.def_id_is_local(def.did()) {
-                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
-                } else if def.is_fundamental() {
-                    args.visit_with(self)
-                } else {
-                    self.found_non_local_ty(ty)
-                }
-            }
-            ty::Foreign(def_id) => {
-                if self.def_id_is_local(def_id) {
-                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
-                } else {
-                    self.found_non_local_ty(ty)
-                }
-            }
-            ty::Dynamic(tt, ..) => {
-                let principal = tt.principal().map(|p| p.def_id());
-                if principal.is_some_and(|p| self.def_id_is_local(p)) {
-                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
-                } else {
-                    self.found_non_local_ty(ty)
-                }
-            }
-            ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
-            ty::Closure(did, ..) | ty::CoroutineClosure(did, ..) | ty::Coroutine(did, ..) => {
-                if self.def_id_is_local(did) {
-                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
-                } else {
-                    self.found_non_local_ty(ty)
-                }
-            }
-            // This should only be created when checking whether we have to check whether some
-            // auto trait impl applies. There will never be multiple impls, so we can just
-            // act as if it were a local type here.
-            ty::CoroutineWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
-        };
-        // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
-        // the first type we visit is always the self type.
-        self.in_self_ty = false;
-        result
-    }
-
-    /// All possible values for a constant parameter already exist
-    /// in the crate defining the trait, so they are always non-local[^1].
-    ///
-    /// Because there's no way to have an impl where the first local
-    /// generic argument is a constant, we also don't have to fail
-    /// the orphan check when encountering a parameter or a generic constant.
-    ///
-    /// This means that we can completely ignore constants during the orphan check.
-    ///
-    /// See `tests/ui/coherence/const-generics-orphan-check-ok.rs` for examples.
-    ///
-    /// [^1]: This might not hold for function pointers or trait objects in the future.
-    /// As these should be quite rare as const arguments and especially rare as impl
-    /// parameters, allowing uncovered const parameters in impls seems more useful
-    /// than allowing `impl<T> Trait<local_fn_ptr, T> for i32` to compile.
-    fn visit_const(&mut self, _c: ty::Const<'tcx>) -> Self::Result {
-        ControlFlow::Continue(())
-    }
-}
-
 /// Compute the `intercrate_ambiguity_causes` for the new solver using
 /// "proof trees".
 ///
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 811f61d2bf3..bdc27e734f9 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -3,10 +3,10 @@ use std::fmt::Debug;
 
 use super::{FromSolverError, TraitEngine};
 use super::{FulfillmentContext, ScrubbedTraitError};
+use crate::error_reporting::traits::TypeErrCtxtExt;
 use crate::regions::InferCtxtRegionExt;
 use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
 use crate::solve::NextSolverError;
-use crate::traits::error_reporting::TypeErrCtxtExt;
 use crate::traits::fulfill::OldSolverError;
 use crate::traits::NormalizeExt;
 use crate::traits::StructurallyNormalizeExt;
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
deleted file mode 100644
index e6cb28df593..00000000000
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-use rustc_hir::def_id::DefId;
-use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt};
-use rustc_infer::traits::util::elaborate;
-use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation};
-use rustc_middle::ty;
-use rustc_span::{Span, DUMMY_SP};
-
-use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::ObligationCtxt;
-
-#[derive(Debug)]
-pub enum CandidateSource {
-    DefId(DefId),
-    ParamEnv(Span),
-}
-
-pub fn compute_applicable_impls_for_diagnostics<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    obligation: &PolyTraitObligation<'tcx>,
-) -> Vec<CandidateSource> {
-    let tcx = infcx.tcx;
-    let param_env = obligation.param_env;
-
-    let predicate_polarity = obligation.predicate.skip_binder().polarity;
-
-    let impl_may_apply = |impl_def_id| {
-        let ocx = ObligationCtxt::new(infcx);
-        infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
-            let obligation_trait_ref = ocx.normalize(
-                &ObligationCause::dummy(),
-                param_env,
-                placeholder_obligation.trait_ref,
-            );
-
-            let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
-            let impl_trait_ref =
-                tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args);
-            let impl_trait_ref =
-                ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
-
-            if let Err(_) =
-                ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref)
-            {
-                return false;
-            }
-
-            let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
-            let impl_polarity = impl_trait_header.polarity;
-
-            match (impl_polarity, predicate_polarity) {
-                (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
-                | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => {}
-                _ => return false,
-            }
-
-            let obligations = tcx
-                .predicates_of(impl_def_id)
-                .instantiate(tcx, impl_args)
-                .into_iter()
-                .map(|(predicate, _)| {
-                    Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
-                })
-                // Kinda hacky, but let's just throw away obligations that overflow.
-                // This may reduce the accuracy of this check (if the obligation guides
-                // inference or it actually resulted in error after others are processed)
-                // ... but this is diagnostics code.
-                .filter(|obligation| {
-                    infcx.next_trait_solver() || infcx.evaluate_obligation(obligation).is_ok()
-                });
-            ocx.register_obligations(obligations);
-
-            ocx.select_where_possible().is_empty()
-        })
-    };
-
-    let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
-        let ocx = ObligationCtxt::new(infcx);
-        infcx.enter_forall(obligation.predicate, |placeholder_obligation| {
-            let obligation_trait_ref = ocx.normalize(
-                &ObligationCause::dummy(),
-                param_env,
-                placeholder_obligation.trait_ref,
-            );
-
-            let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
-                DUMMY_SP,
-                BoundRegionConversionTime::HigherRankedType,
-                poly_trait_predicate,
-            );
-            let param_env_trait_ref =
-                ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref);
-
-            if let Err(_) = ocx.eq(
-                &ObligationCause::dummy(),
-                param_env,
-                obligation_trait_ref,
-                param_env_trait_ref,
-            ) {
-                return false;
-            }
-
-            ocx.select_where_possible().is_empty()
-        })
-    };
-
-    let mut ambiguities = Vec::new();
-
-    tcx.for_each_relevant_impl(
-        obligation.predicate.def_id(),
-        obligation.predicate.skip_binder().trait_ref.self_ty(),
-        |impl_def_id| {
-            if infcx.probe(|_| impl_may_apply(impl_def_id)) {
-                ambiguities.push(CandidateSource::DefId(impl_def_id))
-            }
-        },
-    );
-
-    let predicates =
-        tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx);
-    for (pred, span) in elaborate(tcx, predicates.into_iter()) {
-        let kind = pred.kind();
-        if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
-            && param_env_candidate_may_apply(kind.rebind(trait_pred))
-        {
-            if kind.rebind(trait_pred.trait_ref)
-                == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id()))
-            {
-                ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id())))
-            } else {
-                ambiguities.push(CandidateSource::ParamEnv(span))
-            }
-        }
-    }
-
-    ambiguities
-}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
deleted file mode 100644
index 633d488f7be..00000000000
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ /dev/null
@@ -1,182 +0,0 @@
-// ignore-tidy-filelength :(
-
-pub mod ambiguity;
-mod infer_ctxt_ext;
-pub mod on_unimplemented;
-pub mod suggestions;
-mod type_err_ctxt_ext;
-
-use super::{Obligation, ObligationCause, ObligationCauseCode, PredicateObligation};
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::Visitor;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::Span;
-use std::ops::ControlFlow;
-
-pub use self::infer_ctxt_ext::*;
-pub use self::type_err_ctxt_ext::*;
-
-// When outputting impl candidates, prefer showing those that are more similar.
-//
-// We also compare candidates after skipping lifetimes, which has a lower
-// priority than exact matches.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub enum CandidateSimilarity {
-    Exact { ignoring_lifetimes: bool },
-    Fuzzy { ignoring_lifetimes: bool },
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct ImplCandidate<'tcx> {
-    pub trait_ref: ty::TraitRef<'tcx>,
-    pub similarity: CandidateSimilarity,
-    impl_def_id: DefId,
-}
-
-enum GetSafeTransmuteErrorAndReason {
-    Silent,
-    Error { err_msg: String, safe_transmute_explanation: Option<String> },
-}
-
-struct UnsatisfiedConst(pub bool);
-
-/// Crude way of getting back an `Expr` from a `Span`.
-pub struct FindExprBySpan<'hir> {
-    pub span: Span,
-    pub result: Option<&'hir hir::Expr<'hir>>,
-    pub ty_result: Option<&'hir hir::Ty<'hir>>,
-    pub include_closures: bool,
-    pub tcx: TyCtxt<'hir>,
-}
-
-impl<'hir> FindExprBySpan<'hir> {
-    pub fn new(span: Span, tcx: TyCtxt<'hir>) -> Self {
-        Self { span, result: None, ty_result: None, tcx, include_closures: false }
-    }
-}
-
-impl<'v> Visitor<'v> for FindExprBySpan<'v> {
-    type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
-
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
-    }
-
-    fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
-        if self.span == ex.span {
-            self.result = Some(ex);
-        } else {
-            if let hir::ExprKind::Closure(..) = ex.kind
-                && self.include_closures
-                && let closure_header_sp = self.span.with_hi(ex.span.hi())
-                && closure_header_sp == ex.span
-            {
-                self.result = Some(ex);
-            }
-            hir::intravisit::walk_expr(self, ex);
-        }
-    }
-
-    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
-        if self.span == ty.span {
-            self.ty_result = Some(ty);
-        } else {
-            hir::intravisit::walk_ty(self, ty);
-        }
-    }
-}
-
-/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
-/// `param: ?Sized` would be a valid constraint.
-struct FindTypeParam {
-    param: rustc_span::Symbol,
-    invalid_spans: Vec<Span>,
-    nested: bool,
-}
-
-impl<'v> Visitor<'v> for FindTypeParam {
-    fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
-        // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
-    }
-
-    fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
-        // We collect the spans of all uses of the "bare" type param, like in `field: T` or
-        // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
-        // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
-        // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
-        // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
-        // in that case should make what happened clear enough.
-        match ty.kind {
-            hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
-            hir::TyKind::Path(hir::QPath::Resolved(None, path))
-                if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
-            {
-                if !self.nested {
-                    debug!(?ty, "FindTypeParam::visit_ty");
-                    self.invalid_spans.push(ty.span);
-                }
-            }
-            hir::TyKind::Path(_) => {
-                let prev = self.nested;
-                self.nested = true;
-                hir::intravisit::walk_ty(self, ty);
-                self.nested = prev;
-            }
-            _ => {
-                hir::intravisit::walk_ty(self, ty);
-            }
-        }
-    }
-}
-
-/// Summarizes information
-#[derive(Clone)]
-pub enum ArgKind {
-    /// An argument of non-tuple type. Parameters are (name, ty)
-    Arg(String, String),
-
-    /// An argument of tuple type. For a "found" argument, the span is
-    /// the location in the source of the pattern. For an "expected"
-    /// argument, it will be None. The vector is a list of (name, ty)
-    /// strings for the components of the tuple.
-    Tuple(Option<Span>, Vec<(String, String)>),
-}
-
-impl ArgKind {
-    fn empty() -> ArgKind {
-        ArgKind::Arg("_".to_owned(), "_".to_owned())
-    }
-
-    /// Creates an `ArgKind` from the expected type of an
-    /// argument. It has no name (`_`) and an optional source span.
-    pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
-        match t.kind() {
-            ty::Tuple(tys) => ArgKind::Tuple(
-                span,
-                tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
-            ),
-            _ => ArgKind::Arg("_".to_owned(), t.to_string()),
-        }
-    }
-}
-
-struct HasNumericInferVisitor;
-
-impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor {
-    type Result = ControlFlow<()>;
-
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
-        if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
-            ControlFlow::Break(())
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-}
-
-#[derive(Copy, Clone)]
-pub enum DefIdOrName {
-    DefId(DefId),
-    Name(&'static str),
-}
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index bce5c7101cc..5597c8be592 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,5 +1,5 @@
+use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
 use crate::infer::{InferCtxt, TyOrConstInferVar};
-use crate::traits::error_reporting::TypeErrCtxtExt;
 use crate::traits::normalize::normalize_with_depth_to;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::obligation_forest::ProcessResult;
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 662d95db8ba..703ff2f7f16 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -6,7 +6,6 @@ pub mod auto_trait;
 pub(crate) mod coherence;
 pub mod const_evaluatable;
 mod engine;
-pub mod error_reporting;
 mod fulfill;
 pub mod misc;
 pub mod normalize;
@@ -24,10 +23,10 @@ mod util;
 pub mod vtable;
 pub mod wf;
 
+use crate::error_reporting::traits::TypeErrCtxtExt as _;
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::regions::InferCtxtRegionExt;
-use crate::traits::error_reporting::TypeErrCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_errors::ErrorGuaranteed;
 use rustc_middle::query::Providers;
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index a9ac0f7eb25..dda3aaaf71e 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -1,9 +1,9 @@
 //! Deeply normalize types using the old trait solver.
 
-use super::error_reporting::OverflowCause;
-use super::error_reporting::TypeErrCtxtExt;
 use super::SelectionContext;
 use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
+use crate::error_reporting::traits::OverflowCause;
+use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
 use crate::solve::NextSolverError;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::infer::at::At;
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index f1611bd049d..1c6993bdd37 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -203,7 +203,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
     tcx.associated_items(trait_def_id)
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Type)
-        .flat_map(|item| tcx.explicit_item_bounds(item.def_id).instantiate_identity_iter_copied())
+        .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
         .filter_map(|c| predicate_references_self(tcx, c))
         .collect()
 }
@@ -805,10 +805,11 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
                         .unwrap()
                         .contains(&data.trait_ref(self.tcx).def_id);
 
+                    // only walk contained types if it's not a super trait
                     if is_supertrait_of_current_trait {
-                        ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200
+                        ControlFlow::Continue(())
                     } else {
-                        t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
+                        t.super_visit_with(self) // POSSIBLY reporting an error
                     }
                 }
                 _ => t.super_visit_with(self), // walk contained types, if any
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index bed76b84ee0..c11e86abef8 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -2,11 +2,11 @@
 //! which folds deeply, invoking the underlying
 //! `normalize_canonicalized_projection_ty` query when it encounters projections.
 
+use crate::error_reporting::traits::OverflowCause;
+use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
 use crate::infer::at::At;
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::{InferCtxt, InferOk};
-use crate::traits::error_reporting::OverflowCause;
-use crate::traits::error_reporting::TypeErrCtxtExt;
 use crate::traits::normalize::needs_normalization;
 use crate::traits::Normalized;
 use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
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 b38841db923..8525215a3bc 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
@@ -3,7 +3,6 @@ use crate::traits::wf;
 use crate::traits::ObligationCtxt;
 
 use rustc_infer::infer::canonical::Canonical;
-use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::traits::query::OutlivesBound;
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
@@ -12,6 +11,7 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::DUMMY_SP;
+use rustc_type_ir::outlives::{push_outlives_components, Component};
 use smallvec::{smallvec, SmallVec};
 
 #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
@@ -284,7 +284,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
 /// those relationships.
 fn implied_bounds_from_components<'tcx>(
     sub_region: ty::Region<'tcx>,
-    sup_components: SmallVec<[Component<'tcx>; 4]>,
+    sup_components: SmallVec<[Component<TyCtxt<'tcx>>; 4]>,
 ) -> Vec<OutlivesBound<'tcx>> {
     sup_components
         .into_iter()
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index e36a9ca8bd1..4c3d833b0f9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -571,7 +571,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return;
         }
 
-        let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
+        let drcx = DeepRejectCtxt::new(self.tcx(), TreatParams::ForLookup);
         let obligation_args = obligation.predicate.skip_binder().trait_ref.args;
         self.tcx().for_each_relevant_impl(
             obligation.predicate.def_id(),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 68cc04bc8e6..2c4ffdabf14 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -18,9 +18,9 @@ use super::{
     TraitQueryMode,
 };
 
-use crate::infer::{InferCtxt, InferOk, TypeFreshener};
+use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
+use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
 use crate::solve::InferCtxtSelectExt as _;
-use crate::traits::error_reporting::TypeErrCtxtExt;
 use crate::traits::normalize::normalize_with_depth;
 use crate::traits::normalize::normalize_with_depth_to;
 use crate::traits::project::ProjectAndUnifyResult;
@@ -1523,7 +1523,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // bound regions.
         let trait_ref = predicate.skip_binder().trait_ref;
 
-        coherence::trait_ref_is_knowable::<!>(self.infcx, trait_ref, |ty| Ok(ty)).unwrap()
+        coherence::trait_ref_is_knowable(self.infcx, trait_ref, |ty| Ok::<_, !>(ty)).into_ok()
     }
 
     /// Returns `true` if the global caches can be used.
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index c9bb0d330e1..6a904ef487e 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -14,6 +14,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use specialization_graph::GraphExt;
 
+use crate::error_reporting::traits::to_pretty_impl_header;
 use crate::errors::NegativePositiveConflict;
 use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
@@ -25,8 +26,8 @@ use rustc_errors::{codes::*, Diag, EmissionGuarantee};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::bug;
 use rustc_middle::query::LocalCrate;
+use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
 use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
 use rustc_span::{sym, ErrorGuaranteed, Span, DUMMY_SP};
@@ -485,61 +486,3 @@ fn report_conflicting_impls<'tcx>(
         }
     }
 }
-
-/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
-/// string.
-pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
-    use std::fmt::Write;
-
-    let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity();
-    let mut w = "impl".to_owned();
-
-    let args = GenericArgs::identity_for_item(tcx, impl_def_id);
-
-    // FIXME: Currently only handles ?Sized.
-    //        Needs to support ?Move and ?DynSized when they are implemented.
-    let mut types_without_default_bounds = FxIndexSet::default();
-    let sized_trait = tcx.lang_items().sized_trait();
-
-    let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
-    if !arg_names.is_empty() {
-        types_without_default_bounds.extend(args.types());
-        w.push('<');
-        w.push_str(&arg_names.join(", "));
-        w.push('>');
-    }
-
-    write!(
-        w,
-        " {} for {}",
-        trait_ref.print_only_trait_path(),
-        tcx.type_of(impl_def_id).instantiate_identity()
-    )
-    .unwrap();
-
-    // The predicates will contain default bounds like `T: Sized`. We need to
-    // remove these bounds, and add `T: ?Sized` to any untouched type parameters.
-    let predicates = tcx.predicates_of(impl_def_id).predicates;
-    let mut pretty_predicates =
-        Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
-
-    for (p, _) in predicates {
-        if let Some(poly_trait_ref) = p.as_trait_clause() {
-            if Some(poly_trait_ref.def_id()) == sized_trait {
-                // FIXME(#120456) - is `swap_remove` correct?
-                types_without_default_bounds.swap_remove(&poly_trait_ref.self_ty().skip_binder());
-                continue;
-            }
-        }
-        pretty_predicates.push(p.to_string());
-    }
-
-    pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized")));
-
-    if !pretty_predicates.is_empty() {
-        write!(w, "\n  where {}", pretty_predicates.join(", ")).unwrap();
-    }
-
-    w.push(';');
-    Some(w)
-}
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index e54ced85dee..8f56f9c0f3e 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -6,7 +6,7 @@ use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry};
 use rustc_middle::ty::{GenericArgs, TypeVisitableExt};
-use rustc_span::{sym, Span};
+use rustc_span::{sym, Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
 use std::fmt::Debug;
@@ -285,13 +285,14 @@ fn vtable_entries<'tcx>(
                         return VtblEntry::Vacant;
                     }
 
-                    let instance = ty::Instance::resolve_for_vtable(
+                    let instance = ty::Instance::expect_resolve_for_vtable(
                         tcx,
                         ty::ParamEnv::reveal_all(),
                         def_id,
                         args,
-                    )
-                    .expect("resolution failed during building vtable representation");
+                        DUMMY_SP,
+                    );
+
                     VtblEntry::Method(instance)
                 });
 
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 066755f7b3e..f071dc6c784 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -437,12 +437,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
     /// Pushes the obligations required for an alias (except inherent) to be WF
     /// into `self.out`.
-    fn compute_alias_ty(&mut self, data: ty::AliasTy<'tcx>) {
-        self.compute_alias_term(data.into());
-    }
-
-    /// Pushes the obligations required for an alias (except inherent) to be WF
-    /// into `self.out`.
     fn compute_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
         // A projection is well-formed if
         //
@@ -498,7 +492,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
             self.out.extend(obligations);
         }
 
-        self.compute_projection_args(data.args);
+        data.args.visit_with(self);
     }
 
     fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
@@ -646,8 +640,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
-    type Result = ();
-
     fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
         debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind());
 
@@ -702,8 +694,8 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
             }
 
             ty::Alias(ty::Projection | ty::Opaque | ty::Weak, data) => {
-                self.compute_alias_ty(data);
-                return; // Subtree handled by compute_projection.
+                let obligations = self.nominal_obligations(data.def_id, data.args);
+                self.out.extend(obligations);
             }
             ty::Alias(ty::Inherent, data) => {
                 self.compute_inherent_projection(data);
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index c73ececd1d1..3ee5fd876ff 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -7,7 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt;
 use rustc_trait_selection::traits::{
     ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
     Unimplemented,
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index 0430e0bb70e..2d70fdc3935 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -2,8 +2,8 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
+use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::query::{
     normalize::NormalizationResult, CanonicalAliasGoal, NoSolution,
 };
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index f1dd94839fe..f078cfe1b25 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -127,9 +127,9 @@ fn fn_sig_for_fn_abi<'tcx>(
                     coroutine_kind = ty::ClosureKind::FnOnce;
 
                     // Implementations of `FnMut` and `Fn` for coroutine-closures
-                    // still take their receiver by (mut) ref.
+                    // still take their receiver by ref.
                     if receiver_by_ref {
-                        Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty)
+                        Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty)
                     } else {
                         coroutine_ty
                     }
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index c50a490a9dc..7b6d86d22a5 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -16,7 +16,7 @@ use traits::{translate_args, Reveal};
 
 use crate::errors::UnexpectedFnPtrAssociatedItem;
 
-fn resolve_instance<'tcx>(
+fn resolve_instance_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>,
 ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
@@ -364,5 +364,5 @@ fn resolve_associated_item<'tcx>(
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { resolve_instance, ..*providers };
+    *providers = Providers { resolve_instance_raw, ..*providers };
 }
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 686f2f04ad9..5e91320f897 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -169,10 +169,8 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
                 // Collect opaque types nested within the associated type bounds of this opaque type.
                 // We use identity args here, because we already know that the opaque type uses
                 // only generic parameters, and thus instantiating would not give us more information.
-                for (pred, span) in self
-                    .tcx
-                    .explicit_item_bounds(alias_ty.def_id)
-                    .instantiate_identity_iter_copied()
+                for (pred, span) in
+                    self.tcx.explicit_item_bounds(alias_ty.def_id).iter_identity_copied()
                 {
                     trace!(?pred);
                     self.visit_spanned(span, pred);
diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs
index 97a1b94263e..eb6cb369974 100644
--- a/compiler/rustc_ty_utils/src/sig_types.rs
+++ b/compiler/rustc_ty_utils/src/sig_types.rs
@@ -62,7 +62,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
             }
         }
         DefKind::OpaqueTy => {
-            for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() {
+            for (pred, span) in tcx.explicit_item_bounds(item).iter_identity_copied() {
                 try_visit!(visitor.visit(span, pred));
             }
         }
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index 491ef34430c..2531219baec 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -448,7 +448,7 @@ where
 
     /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
     /// but on an iterator of `TypeFoldable` values.
-    pub fn instantiate_identity_iter(self) -> Iter::IntoIter {
+    pub fn iter_identity(self) -> Iter::IntoIter {
         self.value.into_iter()
     }
 }
@@ -515,9 +515,7 @@ where
 
     /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
     /// but on an iterator of values that deref to a `TypeFoldable`.
-    pub fn instantiate_identity_iter_copied(
-        self,
-    ) -> impl Iterator<Item = <Iter::Item as Deref>::Target> {
+    pub fn iter_identity_copied(self) -> impl Iterator<Item = <Iter::Item as Deref>::Target> {
         self.value.into_iter().map(|v| *v)
     }
 }
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
new file mode 100644
index 00000000000..0def7d12f74
--- /dev/null
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -0,0 +1,305 @@
+use std::marker::PhantomData;
+
+use smallvec::smallvec;
+
+use crate::data_structures::HashSet;
+use crate::outlives::{push_outlives_components, Component};
+use crate::{self as ty, Interner};
+use crate::{inherent::*, Upcast as _};
+
+/// "Elaboration" is the process of identifying all the predicates that
+/// are implied by a source predicate. Currently, this basically means
+/// walking the "supertraits" and other similar assumptions. For example,
+/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
+/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
+/// `T: Foo`, then we know that `T: 'static`.
+pub struct Elaborator<I: Interner, O> {
+    cx: I,
+    stack: Vec<O>,
+    visited: HashSet<ty::Binder<I, ty::PredicateKind<I>>>,
+    mode: Filter,
+}
+
+enum Filter {
+    All,
+    OnlySelf,
+}
+
+/// Describes how to elaborate an obligation into a sub-obligation.
+pub trait Elaboratable<I: Interner> {
+    fn predicate(&self) -> I::Predicate;
+
+    // Makes a new `Self` but with a different clause that comes from elaboration.
+    fn child(&self, clause: I::Clause) -> Self;
+
+    // Makes a new `Self` but with a different clause and a different cause
+    // code (if `Self` has one, such as [`PredicateObligation`]).
+    fn child_with_derived_cause(
+        &self,
+        clause: I::Clause,
+        span: I::Span,
+        parent_trait_pred: ty::Binder<I, ty::TraitPredicate<I>>,
+        index: usize,
+    ) -> Self;
+}
+
+pub fn elaborate<I: Interner, O: Elaboratable<I>>(
+    cx: I,
+    obligations: impl IntoIterator<Item = O>,
+) -> Elaborator<I, O> {
+    let mut elaborator =
+        Elaborator { cx, stack: Vec::new(), visited: HashSet::default(), mode: Filter::All };
+    elaborator.extend_deduped(obligations);
+    elaborator
+}
+
+impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
+    fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
+        // Only keep those bounds that we haven't already seen.
+        // This is necessary to prevent infinite recursion in some
+        // cases. One common case is when people define
+        // `trait Sized: Sized { }` rather than `trait Sized { }`.
+        self.stack.extend(
+            obligations.into_iter().filter(|o| {
+                self.visited.insert(self.cx.anonymize_bound_vars(o.predicate().kind()))
+            }),
+        );
+    }
+
+    /// Filter to only the supertraits of trait predicates, i.e. only the predicates
+    /// that have `Self` as their self type, instead of all implied predicates.
+    pub fn filter_only_self(mut self) -> Self {
+        self.mode = Filter::OnlySelf;
+        self
+    }
+
+    fn elaborate(&mut self, elaboratable: &O) {
+        let cx = self.cx;
+
+        // We only elaborate clauses.
+        let Some(clause) = elaboratable.predicate().as_clause() else {
+            return;
+        };
+
+        let bound_clause = clause.kind();
+        match bound_clause.skip_binder() {
+            ty::ClauseKind::Trait(data) => {
+                // Negative trait bounds do not imply any supertrait bounds
+                if data.polarity != ty::PredicatePolarity::Positive {
+                    return;
+                }
+
+                let map_to_child_clause =
+                    |(index, (clause, span)): (usize, (I::Clause, I::Span))| {
+                        elaboratable.child_with_derived_cause(
+                            clause.instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
+                            span,
+                            bound_clause.rebind(data),
+                            index,
+                        )
+                    };
+
+                // Get predicates implied by the trait, or only super predicates if we only care about self predicates.
+                match self.mode {
+                    Filter::All => self.extend_deduped(
+                        cx.explicit_implied_predicates_of(data.def_id())
+                            .iter_identity()
+                            .enumerate()
+                            .map(map_to_child_clause),
+                    ),
+                    Filter::OnlySelf => self.extend_deduped(
+                        cx.explicit_super_predicates_of(data.def_id())
+                            .iter_identity()
+                            .enumerate()
+                            .map(map_to_child_clause),
+                    ),
+                };
+            }
+            ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
+                // We know that `T: 'a` for some type `T`. We can
+                // often elaborate this. For example, if we know that
+                // `[U]: 'a`, that implies that `U: 'a`. Similarly, if
+                // we know `&'a U: 'b`, then we know that `'a: 'b` and
+                // `U: 'b`.
+                //
+                // We can basically ignore bound regions here. So for
+                // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
+                // `'a: 'b`.
+
+                // Ignore `for<'a> T: 'a` -- we might in the future
+                // consider this as evidence that `T: 'static`, but
+                // I'm a bit wary of such constructions and so for now
+                // I want to be conservative. --nmatsakis
+                if r_min.is_bound() {
+                    return;
+                }
+
+                let mut components = smallvec![];
+                push_outlives_components(cx, ty_max, &mut components);
+                self.extend_deduped(
+                    components
+                        .into_iter()
+                        .filter_map(|component| elaborate_component_to_clause(cx, component, r_min))
+                        .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(cx))),
+                );
+            }
+            ty::ClauseKind::RegionOutlives(..) => {
+                // Nothing to elaborate from `'a: 'b`.
+            }
+            ty::ClauseKind::WellFormed(..) => {
+                // Currently, we do not elaborate WF predicates,
+                // although we easily could.
+            }
+            ty::ClauseKind::Projection(..) => {
+                // Nothing to elaborate in a projection predicate.
+            }
+            ty::ClauseKind::ConstEvaluatable(..) => {
+                // Currently, we do not elaborate const-evaluatable
+                // predicates.
+            }
+            ty::ClauseKind::ConstArgHasType(..) => {
+                // Nothing to elaborate
+            }
+        }
+    }
+}
+
+fn elaborate_component_to_clause<I: Interner>(
+    cx: I,
+    component: Component<I>,
+    outlives_region: I::Region,
+) -> Option<ty::ClauseKind<I>> {
+    match component {
+        Component::Region(r) => {
+            if r.is_bound() {
+                None
+            } else {
+                Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r, outlives_region)))
+            }
+        }
+
+        Component::Param(p) => {
+            let ty = Ty::new_param(cx, p);
+            Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region)))
+        }
+
+        Component::Placeholder(p) => {
+            let ty = Ty::new_placeholder(cx, p);
+            Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region)))
+        }
+
+        Component::UnresolvedInferenceVariable(_) => None,
+
+        Component::Alias(alias_ty) => {
+            // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
+            // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
+            Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
+                alias_ty.to_ty(cx),
+                outlives_region,
+            )))
+        }
+
+        Component::EscapingAlias(_) => {
+            // We might be able to do more here, but we don't
+            // want to deal with escaping vars right now.
+            None
+        }
+    }
+}
+
+impl<I: Interner, O: Elaboratable<I>> Iterator for Elaborator<I, O> {
+    type Item = O;
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.stack.len(), None)
+    }
+
+    fn next(&mut self) -> Option<Self::Item> {
+        // Extract next item from top-most stack frame, if any.
+        if let Some(obligation) = self.stack.pop() {
+            self.elaborate(&obligation);
+            Some(obligation)
+        } else {
+            None
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Supertrait iterator
+///////////////////////////////////////////////////////////////////////////
+
+/// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally)
+/// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
+/// to identify which traits may define a given associated type to help avoid cycle errors,
+/// and to make size estimates for vtable layout computation.
+pub fn supertrait_def_ids<I: Interner>(
+    cx: I,
+    trait_def_id: I::DefId,
+) -> impl Iterator<Item = I::DefId> {
+    let mut set = HashSet::default();
+    let mut stack = vec![trait_def_id];
+
+    set.insert(trait_def_id);
+
+    std::iter::from_fn(move || {
+        let trait_def_id = stack.pop()?;
+
+        for (predicate, _) in cx.explicit_super_predicates_of(trait_def_id).iter_identity() {
+            if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() {
+                if set.insert(data.def_id()) {
+                    stack.push(data.def_id());
+                }
+            }
+        }
+
+        Some(trait_def_id)
+    })
+}
+
+pub fn supertraits<I: Interner>(
+    tcx: I,
+    trait_ref: ty::Binder<I, ty::TraitRef<I>>,
+) -> FilterToTraits<I, Elaborator<I, I::Clause>> {
+    elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits()
+}
+
+pub fn transitive_bounds<I: Interner>(
+    tcx: I,
+    trait_refs: impl Iterator<Item = ty::Binder<I, ty::TraitRef<I>>>,
+) -> FilterToTraits<I, Elaborator<I, I::Clause>> {
+    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
+        .filter_only_self()
+        .filter_to_traits()
+}
+
+impl<I: Interner> Elaborator<I, I::Clause> {
+    fn filter_to_traits(self) -> FilterToTraits<I, Self> {
+        FilterToTraits { _cx: PhantomData, base_iterator: self }
+    }
+}
+
+/// A filter around an iterator of predicates that makes it yield up
+/// just trait references.
+pub struct FilterToTraits<I: Interner, It: Iterator<Item = I::Clause>> {
+    _cx: PhantomData<I>,
+    base_iterator: It,
+}
+
+impl<I: Interner, It: Iterator<Item = I::Clause>> Iterator for FilterToTraits<I, It> {
+    type Item = ty::Binder<I, ty::TraitRef<I>>;
+
+    fn next(&mut self) -> Option<ty::Binder<I, ty::TraitRef<I>>> {
+        while let Some(pred) = self.base_iterator.next() {
+            if let Some(data) = pred.as_trait_clause() {
+                return Some(data.map_bound(|t| t.trait_ref));
+            }
+        }
+        None
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let (_, upper) = self.base_iterator.size_hint();
+        (0, upper)
+    }
+}
diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs
new file mode 100644
index 00000000000..0810fa5c558
--- /dev/null
+++ b/compiler/rustc_type_ir/src/fast_reject.rs
@@ -0,0 +1,397 @@
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::iter;
+use std::marker::PhantomData;
+
+use rustc_ast_ir::Mutability;
+#[cfg(feature = "nightly")]
+use rustc_data_structures::fingerprint::Fingerprint;
+#[cfg(feature = "nightly")]
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+#[cfg(feature = "nightly")]
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+
+use crate::inherent::*;
+use crate::visit::TypeVisitableExt as _;
+use crate::{self as ty, Interner};
+
+/// See `simplify_type`.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+pub enum SimplifiedType<DefId> {
+    Bool,
+    Char,
+    Int(ty::IntTy),
+    Uint(ty::UintTy),
+    Float(ty::FloatTy),
+    Adt(DefId),
+    Foreign(DefId),
+    Str,
+    Array,
+    Slice,
+    Ref(Mutability),
+    Ptr(Mutability),
+    Never,
+    Tuple(usize),
+    /// A trait object, all of whose components are markers
+    /// (e.g., `dyn Send + Sync`).
+    MarkerTraitObject,
+    Trait(DefId),
+    Closure(DefId),
+    Coroutine(DefId),
+    CoroutineWitness(DefId),
+    Function(usize),
+    Placeholder,
+    Error,
+}
+
+#[cfg(feature = "nightly")]
+impl<HCX: Clone, DefId: HashStable<HCX>> ToStableHashKey<HCX> for SimplifiedType<DefId> {
+    type KeyType = Fingerprint;
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &HCX) -> Fingerprint {
+        let mut hasher = StableHasher::new();
+        let mut hcx: HCX = hcx.clone();
+        self.hash_stable(&mut hcx, &mut hasher);
+        hasher.finish()
+    }
+}
+
+/// Generic parameters are pretty much just bound variables, e.g.
+/// the type of `fn foo<'a, T>(x: &'a T) -> u32 { ... }` can be thought of as
+/// `for<'a, T> fn(&'a T) -> u32`.
+///
+/// Typecheck of `foo` has to succeed for all possible generic arguments, so
+/// during typeck, we have to treat its generic parameters as if they
+/// were placeholders.
+///
+/// But when calling `foo` we only have to provide a specific generic argument.
+/// In that case the generic parameters are instantiated with inference variables.
+/// As we use `simplify_type` before that instantiation happens, we just treat
+/// generic parameters as if they were inference variables in that case.
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
+pub enum TreatParams {
+    /// Treat parameters as infer vars. This is the correct mode for caching
+    /// an impl's type for lookup.
+    AsCandidateKey,
+    /// Treat parameters as placeholders in the given environment. This is the
+    /// correct mode for *lookup*, as during candidate selection.
+    ///
+    /// This also treats projections with inference variables as infer vars
+    /// since they could be further normalized.
+    ForLookup,
+}
+
+/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
+///
+/// **This function should only be used if you need to store or retrieve the type from some
+/// hashmap. If you want to quickly decide whether two types may unify, use the [DeepRejectCtxt]
+/// instead.**
+///
+/// The idea is to get something simple that we can use to quickly decide if two types could unify,
+/// for example during method lookup. If this function returns `Some(x)` it can only unify with
+/// types for which this method returns either `Some(x)` as well or `None`.
+///
+/// A special case here are parameters and projections, which are only injective
+/// if they are treated as placeholders.
+///
+/// For example when storing impls based on their simplified self type, we treat
+/// generic parameters as if they were inference variables. We must not simplify them here,
+/// as they can unify with any other type.
+///
+/// With projections we have to be even more careful, as treating them as placeholders
+/// is only correct if they are fully normalized.
+///
+/// ¹ meaning that if the outermost layers are different, then the whole types are also different.
+pub fn simplify_type<I: Interner>(
+    tcx: I,
+    ty: I::Ty,
+    treat_params: TreatParams,
+) -> Option<SimplifiedType<I::DefId>> {
+    match ty.kind() {
+        ty::Bool => Some(SimplifiedType::Bool),
+        ty::Char => Some(SimplifiedType::Char),
+        ty::Int(int_type) => Some(SimplifiedType::Int(int_type)),
+        ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)),
+        ty::Float(float_type) => Some(SimplifiedType::Float(float_type)),
+        ty::Adt(def, _) => Some(SimplifiedType::Adt(def.def_id())),
+        ty::Str => Some(SimplifiedType::Str),
+        ty::Array(..) => Some(SimplifiedType::Array),
+        ty::Slice(..) => Some(SimplifiedType::Slice),
+        ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params),
+        ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)),
+        ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
+            Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
+                Some(SimplifiedType::Trait(principal_def_id))
+            }
+            _ => Some(SimplifiedType::MarkerTraitObject),
+        },
+        ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
+        ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => {
+            Some(SimplifiedType::Closure(def_id))
+        }
+        ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)),
+        ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)),
+        ty::Never => Some(SimplifiedType::Never),
+        ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
+        ty::FnPtr(f) => Some(SimplifiedType::Function(f.skip_binder().inputs().len())),
+        ty::Placeholder(..) => Some(SimplifiedType::Placeholder),
+        ty::Param(_) => match treat_params {
+            TreatParams::ForLookup => Some(SimplifiedType::Placeholder),
+            TreatParams::AsCandidateKey => None,
+        },
+        ty::Alias(..) => match treat_params {
+            // When treating `ty::Param` as a placeholder, projections also
+            // don't unify with anything else as long as they are fully normalized.
+            // FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder`
+            // when the new solver is enabled by default.
+            TreatParams::ForLookup if !ty.has_non_region_infer() => {
+                Some(SimplifiedType::Placeholder)
+            }
+            TreatParams::ForLookup | TreatParams::AsCandidateKey => None,
+        },
+        ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)),
+        ty::Error(_) => Some(SimplifiedType::Error),
+        ty::Bound(..) | ty::Infer(_) => None,
+    }
+}
+
+impl<DefId> SimplifiedType<DefId> {
+    pub fn def(self) -> Option<DefId> {
+        match self {
+            SimplifiedType::Adt(d)
+            | SimplifiedType::Foreign(d)
+            | SimplifiedType::Trait(d)
+            | SimplifiedType::Closure(d)
+            | SimplifiedType::Coroutine(d)
+            | SimplifiedType::CoroutineWitness(d) => Some(d),
+            _ => None,
+        }
+    }
+}
+
+/// Given generic arguments from an obligation and an impl,
+/// could these two be unified after replacing parameters in the
+/// the impl with inference variables.
+///
+/// For obligations, parameters won't be replaced by inference
+/// variables and only unify with themselves. We treat them
+/// the same way we treat placeholders.
+///
+/// We also use this function during coherence. For coherence the
+/// impls only have to overlap for some value, so we treat parameters
+/// on both sides like inference variables. This behavior is toggled
+/// using the `treat_obligation_params` field.
+#[derive(Debug, Clone, Copy)]
+pub struct DeepRejectCtxt<I: Interner> {
+    treat_obligation_params: TreatParams,
+    _interner: PhantomData<I>,
+}
+
+impl<I: Interner> DeepRejectCtxt<I> {
+    pub fn new(_interner: I, treat_obligation_params: TreatParams) -> Self {
+        DeepRejectCtxt { treat_obligation_params, _interner: PhantomData }
+    }
+
+    pub fn args_may_unify(
+        self,
+        obligation_args: I::GenericArgs,
+        impl_args: I::GenericArgs,
+    ) -> bool {
+        iter::zip(obligation_args.iter(), impl_args.iter()).all(|(obl, imp)| {
+            match (obl.kind(), imp.kind()) {
+                // We don't fast reject based on regions.
+                (ty::GenericArgKind::Lifetime(_), ty::GenericArgKind::Lifetime(_)) => true,
+                (ty::GenericArgKind::Type(obl), ty::GenericArgKind::Type(imp)) => {
+                    self.types_may_unify(obl, imp)
+                }
+                (ty::GenericArgKind::Const(obl), ty::GenericArgKind::Const(imp)) => {
+                    self.consts_may_unify(obl, imp)
+                }
+                _ => panic!("kind mismatch: {obl:?} {imp:?}"),
+            }
+        })
+    }
+
+    pub fn types_may_unify(self, obligation_ty: I::Ty, impl_ty: I::Ty) -> bool {
+        match impl_ty.kind() {
+            // Start by checking whether the type in the impl may unify with
+            // pretty much everything. Just return `true` in that case.
+            ty::Param(_) | ty::Error(_) | ty::Alias(..) => return true,
+            // These types only unify with inference variables or their own
+            // variant.
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Adt(..)
+            | ty::Str
+            | ty::Array(..)
+            | ty::Slice(..)
+            | ty::RawPtr(..)
+            | ty::Dynamic(..)
+            | ty::Pat(..)
+            | ty::Ref(..)
+            | ty::Never
+            | ty::Tuple(..)
+            | ty::FnPtr(..)
+            | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()),
+            ty::FnDef(..)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
+            | ty::Coroutine(..)
+            | ty::CoroutineWitness(..)
+            | ty::Placeholder(..)
+            | ty::Bound(..)
+            | ty::Infer(_) => panic!("unexpected impl_ty: {impl_ty:?}"),
+        }
+
+        let k = impl_ty.kind();
+        match obligation_ty.kind() {
+            // Purely rigid types, use structural equivalence.
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Str
+            | ty::Never
+            | ty::Foreign(_) => obligation_ty == impl_ty,
+            ty::Ref(_, obl_ty, obl_mutbl) => match k {
+                ty::Ref(_, impl_ty, impl_mutbl) => {
+                    obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty)
+                }
+                _ => false,
+            },
+            ty::Adt(obl_def, obl_args) => match k {
+                ty::Adt(impl_def, impl_args) => {
+                    obl_def == impl_def && self.args_may_unify(obl_args, impl_args)
+                }
+                _ => false,
+            },
+            ty::Pat(obl_ty, _) => {
+                // FIXME(pattern_types): take pattern into account
+                matches!(k, ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty))
+            }
+            ty::Slice(obl_ty) => {
+                matches!(k, ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty))
+            }
+            ty::Array(obl_ty, obl_len) => match k {
+                ty::Array(impl_ty, impl_len) => {
+                    self.types_may_unify(obl_ty, impl_ty)
+                        && self.consts_may_unify(obl_len, impl_len)
+                }
+                _ => false,
+            },
+            ty::Tuple(obl) => match k {
+                ty::Tuple(imp) => {
+                    obl.len() == imp.len()
+                        && iter::zip(obl.iter(), imp.iter())
+                            .all(|(obl, imp)| self.types_may_unify(obl, imp))
+                }
+                _ => false,
+            },
+            ty::RawPtr(obl_ty, obl_mutbl) => match k {
+                ty::RawPtr(imp_ty, imp_mutbl) => {
+                    obl_mutbl == imp_mutbl && self.types_may_unify(obl_ty, imp_ty)
+                }
+                _ => false,
+            },
+            ty::Dynamic(obl_preds, ..) => {
+                // Ideally we would walk the existential predicates here or at least
+                // compare their length. But considering that the relevant `Relate` impl
+                // actually sorts and deduplicates these, that doesn't work.
+                matches!(k, ty::Dynamic(impl_preds, ..) if
+                    obl_preds.principal_def_id() == impl_preds.principal_def_id()
+                )
+            }
+            ty::FnPtr(obl_sig) => match k {
+                ty::FnPtr(impl_sig) => {
+                    let ty::FnSig { inputs_and_output, c_variadic, safety, abi } =
+                        obl_sig.skip_binder();
+                    let impl_sig = impl_sig.skip_binder();
+
+                    abi == impl_sig.abi
+                        && c_variadic == impl_sig.c_variadic
+                        && safety == impl_sig.safety
+                        && inputs_and_output.len() == impl_sig.inputs_and_output.len()
+                        && iter::zip(inputs_and_output.iter(), impl_sig.inputs_and_output.iter())
+                            .all(|(obl, imp)| self.types_may_unify(obl, imp))
+                }
+                _ => false,
+            },
+
+            // Impls cannot contain these types as these cannot be named directly.
+            ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => false,
+
+            // Placeholder types don't unify with anything on their own
+            ty::Placeholder(..) | ty::Bound(..) => false,
+
+            // Depending on the value of `treat_obligation_params`, we either
+            // treat generic parameters like placeholders or like inference variables.
+            ty::Param(_) => match self.treat_obligation_params {
+                TreatParams::ForLookup => false,
+                TreatParams::AsCandidateKey => true,
+            },
+
+            ty::Infer(ty::IntVar(_)) => impl_ty.is_integral(),
+
+            ty::Infer(ty::FloatVar(_)) => impl_ty.is_floating_point(),
+
+            ty::Infer(_) => true,
+
+            // As we're walking the whole type, it may encounter projections
+            // inside of binders and what not, so we're just going to assume that
+            // projections can unify with other stuff.
+            //
+            // Looking forward to lazy normalization this is the safer strategy anyways.
+            ty::Alias(..) => true,
+
+            ty::Error(_) => true,
+
+            ty::CoroutineWitness(..) => {
+                panic!("unexpected obligation type: {:?}", obligation_ty)
+            }
+        }
+    }
+
+    pub fn consts_may_unify(self, obligation_ct: I::Const, impl_ct: I::Const) -> bool {
+        let impl_val = match impl_ct.kind() {
+            ty::ConstKind::Expr(_)
+            | ty::ConstKind::Param(_)
+            | ty::ConstKind::Unevaluated(_)
+            | ty::ConstKind::Error(_) => {
+                return true;
+            }
+            ty::ConstKind::Value(_, impl_val) => impl_val,
+            ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
+                panic!("unexpected impl arg: {:?}", impl_ct)
+            }
+        };
+
+        match obligation_ct.kind() {
+            ty::ConstKind::Param(_) => match self.treat_obligation_params {
+                TreatParams::ForLookup => false,
+                TreatParams::AsCandidateKey => true,
+            },
+
+            // Placeholder consts don't unify with anything on their own
+            ty::ConstKind::Placeholder(_) => false,
+
+            // As we don't necessarily eagerly evaluate constants,
+            // they might unify with any value.
+            ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => {
+                true
+            }
+            ty::ConstKind::Value(_, obl_val) => obl_val == impl_val,
+
+            ty::ConstKind::Infer(_) => true,
+
+            ty::ConstKind::Bound(..) => {
+                panic!("unexpected obl const: {:?}", obligation_ct)
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
new file mode 100644
index 00000000000..1d0b2345b80
--- /dev/null
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -0,0 +1,98 @@
+use crate::fold::TypeFoldable;
+use crate::relate::Relate;
+use crate::solve::{Goal, NoSolution, SolverMode};
+use crate::{self as ty, Interner};
+
+pub trait InferCtxtLike: Sized {
+    type Interner: Interner;
+    fn cx(&self) -> Self::Interner;
+
+    fn solver_mode(&self) -> SolverMode;
+
+    fn universe(&self) -> ty::UniverseIndex;
+    fn create_next_universe(&self) -> ty::UniverseIndex;
+
+    fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
+    fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
+    fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
+
+    fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
+    fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
+
+    fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_float_var(
+        &self,
+        vid: ty::FloatVid,
+    ) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_ct_var(
+        &self,
+        vid: ty::ConstVid,
+    ) -> <Self::Interner as Interner>::Const;
+    fn opportunistic_resolve_effect_var(
+        &self,
+        vid: ty::EffectVid,
+    ) -> <Self::Interner as Interner>::Const;
+    fn opportunistic_resolve_lt_var(
+        &self,
+        vid: ty::RegionVid,
+    ) -> <Self::Interner as Interner>::Region;
+
+    fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
+
+    fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
+    fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
+    fn fresh_args_for_item(
+        &self,
+        def_id: <Self::Interner as Interner>::DefId,
+    ) -> <Self::Interner as Interner>::GenericArgs;
+
+    fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
+        &self,
+        value: ty::Binder<Self::Interner, T>,
+    ) -> T;
+
+    fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
+        &self,
+        value: ty::Binder<Self::Interner, T>,
+        f: impl FnOnce(T) -> U,
+    ) -> U;
+
+    fn relate<T: Relate<Self::Interner>>(
+        &self,
+        param_env: <Self::Interner as Interner>::ParamEnv,
+        lhs: T,
+        variance: ty::Variance,
+        rhs: T,
+    ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
+
+    fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
+        &self,
+        param_env: <Self::Interner as Interner>::ParamEnv,
+        lhs: T,
+        rhs: T,
+    ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
+
+    fn shallow_resolve(
+        &self,
+        ty: <Self::Interner as Interner>::Ty,
+    ) -> <Self::Interner as Interner>::Ty;
+
+    fn resolve_vars_if_possible<T>(&self, value: T) -> T
+    where
+        T: TypeFoldable<Self::Interner>;
+
+    fn probe<T>(&self, probe: impl FnOnce() -> T) -> T;
+
+    fn sub_regions(
+        &self,
+        sub: <Self::Interner as Interner>::Region,
+        sup: <Self::Interner as Interner>::Region,
+    );
+
+    fn register_ty_outlives(
+        &self,
+        ty: <Self::Interner as Interner>::Ty,
+        r: <Self::Interner as Interner>::Region,
+    );
+}
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index a4e1a97d505..de86a8536f7 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -9,6 +9,7 @@ use std::hash::Hash;
 use rustc_ast_ir::Mutability;
 
 use crate::data_structures::HashSet;
+use crate::elaborate::Elaboratable;
 use crate::fold::{TypeFoldable, TypeSuperFoldable};
 use crate::relate::Relate;
 use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal};
@@ -40,6 +41,10 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn new_var(interner: I, var: ty::TyVid) -> Self;
 
+    fn new_param(interner: I, param: I::ParamTy) -> Self;
+
+    fn new_placeholder(interner: I, param: I::PlaceholderTy) -> Self;
+
     fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundTy) -> Self;
 
     fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
@@ -120,6 +125,14 @@ pub trait Ty<I: Interner<Ty = Self>>:
         matches!(self.kind(), ty::Infer(ty::TyVar(_)))
     }
 
+    fn is_floating_point(self) -> bool {
+        matches!(self.kind(), ty::Float(_) | ty::Infer(ty::FloatVar(_)))
+    }
+
+    fn is_integral(self) -> bool {
+        matches!(self.kind(), ty::Infer(ty::IntVar(_)) | ty::Int(_) | ty::Uint(_))
+    }
+
     fn is_fn_ptr(self) -> bool {
         matches!(self.kind(), ty::FnPtr(_))
     }
@@ -224,6 +237,10 @@ pub trait Region<I: Interner<Region = Self>>:
     fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
 
     fn new_static(interner: I) -> Self;
+
+    fn is_bound(self) -> bool {
+        matches!(self.kind(), ty::ReBound(..))
+    }
 }
 
 pub trait Const<I: Interner<Const = Self>>:
@@ -264,6 +281,10 @@ pub trait Const<I: Interner<Const = Self>>:
     }
 }
 
+pub trait ExprConst<I: Interner<ExprConst = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
+    fn args(self) -> I::GenericArgs;
+}
+
 pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
     fn count(&self) -> usize;
 }
@@ -413,6 +434,8 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
     + UpcastFrom<I, ty::OutlivesPredicate<I, I::Region>>
     + IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>>
 {
+    fn as_clause(self) -> Option<I::Clause>;
+
     fn is_coinductive(self, interner: I) -> bool;
 
     // FIXME: Eventually uplift the impl out of rustc and make this defaulted.
@@ -425,35 +448,35 @@ pub trait Clause<I: Interner<Clause = Self>>:
     + Hash
     + Eq
     + TypeFoldable<I>
-    // FIXME: Remove these, uplift the `Upcast` impls.
+    + UpcastFrom<I, ty::Binder<I, ty::ClauseKind<I>>>
     + UpcastFrom<I, ty::TraitRef<I>>
     + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
     + UpcastFrom<I, ty::ProjectionPredicate<I>>
     + UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
     + IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>
+    + Elaboratable<I>
 {
     fn as_trait_clause(self) -> Option<ty::Binder<I, ty::TraitPredicate<I>>> {
         self.kind()
-            .map_bound(|clause| {
-                if let ty::ClauseKind::Trait(t) = clause {
-                    Some(t)
-                } else {
-                    None
-                }
-            })
+            .map_bound(|clause| if let ty::ClauseKind::Trait(t) = clause { Some(t) } else { None })
             .transpose()
     }
+
     fn as_projection_clause(self) -> Option<ty::Binder<I, ty::ProjectionPredicate<I>>> {
         self.kind()
-            .map_bound(|clause| {
-                if let ty::ClauseKind::Projection(p) = clause {
-                    Some(p)
-                } else {
-                    None
-                }
-            })
+            .map_bound(
+                |clause| {
+                    if let ty::ClauseKind::Projection(p) = clause { Some(p) } else { None }
+                },
+            )
             .transpose()
     }
+
+    /// Performs a instantiation suitable for going from a
+    /// poly-trait-ref to supertraits that must hold if that
+    /// poly-trait-ref holds. This is slightly different from a normal
+    /// instantiation in terms of what happens with bound regions.
+    fn instantiate_supertrait(self, tcx: I, trait_ref: ty::Binder<I, ty::TraitRef<I>>) -> Self;
 }
 
 /// Common capabilities of placeholder kinds
@@ -498,6 +521,8 @@ pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
     fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl IntoIterator<Item = I::Ty>>;
 
     fn sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
+
+    fn is_fundamental(self) -> bool;
 }
 
 pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
@@ -542,6 +567,8 @@ pub trait EvaluationCache<I: Interner> {
 }
 
 pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
+    fn is_local(self) -> bool;
+
     fn as_local(self) -> Option<I::LocalDefId>;
 }
 
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 6665158c7cd..fdd1553d389 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -32,6 +32,7 @@ pub trait Interner:
 {
     type DefId: DefId<Self>;
     type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
+    type Span: Copy + Debug + Hash + Eq + TypeFoldable<Self>;
 
     type GenericArgs: GenericArgs<Self>;
     type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike<Item = Self::GenericArg>;
@@ -109,7 +110,7 @@ pub trait Interner:
     type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
     type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
     type ValueConst: Copy + Debug + Hash + Eq;
-    type ExprConst: Copy + Debug + Hash + Eq + Relate<Self>;
+    type ExprConst: ExprConst<Self>;
 
     // Kinds of regions
     type Region: Region<Self>;
@@ -212,7 +213,12 @@ pub trait Interner:
     fn explicit_super_predicates_of(
         self,
         def_id: Self::DefId,
-    ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
+    ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>;
+
+    fn explicit_implied_predicates_of(
+        self,
+        def_id: Self::DefId,
+    ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>;
 
     fn has_target_features(self, def_id: Self::DefId) -> bool;
 
@@ -220,14 +226,9 @@ pub trait Interner:
 
     fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool;
 
-    fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
+    fn as_lang_item(self, def_id: Self::DefId) -> Option<TraitSolverLangItem>;
 
-    // FIXME: move `fast_reject` into `rustc_type_ir`.
-    fn args_may_unify_deep(
-        self,
-        obligation_args: Self::GenericArgs,
-        impl_args: Self::GenericArgs,
-    ) -> bool;
+    fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
 
     fn for_each_relevant_impl(
         self,
@@ -250,14 +251,9 @@ pub trait Interner:
 
     fn trait_is_object_safe(self, trait_def_id: Self::DefId) -> bool;
 
-    fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool;
-
-    fn fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option<ty::ClosureKind>;
-
-    fn async_fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option<ty::ClosureKind>;
+    fn trait_is_fundamental(self, def_id: Self::DefId) -> bool;
 
-    fn supertrait_def_ids(self, trait_def_id: Self::DefId)
-    -> impl IntoIterator<Item = Self::DefId>;
+    fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool;
 
     fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed;
 
@@ -276,6 +272,11 @@ pub trait Interner:
         param_env: Self::ParamEnv,
         placeholder: Self::PlaceholderConst,
     ) -> Self::Ty;
+
+    fn anonymize_bound_vars<T: TypeFoldable<Self>>(
+        self,
+        binder: ty::Binder<Self, T>,
+    ) -> ty::Binder<Self, T>;
 }
 
 /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index cf00c37caa2..265a4118827 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -3,8 +3,11 @@
 pub enum TraitSolverLangItem {
     // tidy-alphabetical-start
     AsyncDestruct,
+    AsyncFn,
     AsyncFnKindHelper,
     AsyncFnKindUpvars,
+    AsyncFnMut,
+    AsyncFnOnce,
     AsyncFnOnceOutput,
     AsyncIterator,
     CallOnceFuture,
@@ -22,6 +25,9 @@ pub enum TraitSolverLangItem {
     EffectsMaybe,
     EffectsNoRuntime,
     EffectsRuntime,
+    Fn,
+    FnMut,
+    FnOnce,
     FnPtrTrait,
     FusedIterator,
     Future,
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index d7442e7c89c..b14a65fc779 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -2,7 +2,7 @@
 #![allow(rustc::usage_of_ty_tykind)]
 #![cfg_attr(
     feature = "nightly",
-    feature(associated_type_defaults, min_specialization, never_type, rustc_attrs, negative_impls)
+    feature(associated_type_defaults, never_type, rustc_attrs, negative_impls)
 )]
 #![cfg_attr(feature = "nightly", allow(internal_features))]
 // tidy-alphabetical-end
@@ -20,12 +20,15 @@ pub mod visit;
 #[cfg(feature = "nightly")]
 pub mod codec;
 pub mod data_structures;
+pub mod elaborate;
 pub mod error;
+pub mod fast_reject;
 pub mod fold;
 pub mod inherent;
 pub mod ir_print;
 pub mod lang_items;
 pub mod lift;
+pub mod outlives;
 pub mod relate;
 pub mod solve;
 
@@ -38,6 +41,7 @@ mod const_kind;
 mod effects;
 mod flags;
 mod generic_arg;
+mod infer_ctxt;
 mod interner;
 mod opaque_ty;
 mod predicate;
@@ -55,6 +59,7 @@ pub use const_kind::*;
 pub use effects::*;
 pub use flags::*;
 pub use generic_arg::*;
+pub use infer_ctxt::*;
 pub use interner::*;
 pub use opaque_ty::*;
 pub use predicate::*;
diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs
new file mode 100644
index 00000000000..10b6f3355d9
--- /dev/null
+++ b/compiler/rustc_type_ir/src/outlives.rs
@@ -0,0 +1,228 @@
+//! The outlives relation `T: 'a` or `'a: 'b`. This code frequently
+//! refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
+//! RFC for reference.
+
+use smallvec::{smallvec, SmallVec};
+
+use crate::data_structures::SsoHashSet;
+use crate::inherent::*;
+use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, TypeVisitor};
+use crate::{self as ty, Interner};
+
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = ""))]
+pub enum Component<I: Interner> {
+    Region(I::Region),
+    Param(I::ParamTy),
+    Placeholder(I::PlaceholderTy),
+    UnresolvedInferenceVariable(ty::InferTy),
+
+    // Projections like `T::Foo` are tricky because a constraint like
+    // `T::Foo: 'a` can be satisfied in so many ways. There may be a
+    // where-clause that says `T::Foo: 'a`, or the defining trait may
+    // include a bound like `type Foo: 'static`, or -- in the most
+    // conservative way -- we can prove that `T: 'a` (more generally,
+    // that all components in the projection outlive `'a`). This code
+    // is not in a position to judge which is the best technique, so
+    // we just product the projection as a component and leave it to
+    // the consumer to decide (but see `EscapingProjection` below).
+    Alias(ty::AliasTy<I>),
+
+    // In the case where a projection has escaping regions -- meaning
+    // regions bound within the type itself -- we always use
+    // the most conservative rule, which requires that all components
+    // outlive the bound. So for example if we had a type like this:
+    //
+    //     for<'a> Trait1<  <T as Trait2<'a,'b>>::Foo  >
+    //                      ~~~~~~~~~~~~~~~~~~~~~~~~~
+    //
+    // then the inner projection (underlined) has an escaping region
+    // `'a`. We consider that outer trait `'c` to meet a bound if `'b`
+    // outlives `'b: 'c`, and we don't consider whether the trait
+    // declares that `Foo: 'static` etc. Therefore, we just return the
+    // free components of such a projection (in this case, `'b`).
+    //
+    // However, in the future, we may want to get smarter, and
+    // actually return a "higher-ranked projection" here. Therefore,
+    // we mark that these components are part of an escaping
+    // projection, so that implied bounds code can avoid relying on
+    // them. This gives us room to improve the regionck reasoning in
+    // the future without breaking backwards compat.
+    EscapingAlias(Vec<Component<I>>),
+}
+
+/// Push onto `out` all the things that must outlive `'a` for the condition
+/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
+pub fn push_outlives_components<I: Interner>(
+    tcx: I,
+    ty: I::Ty,
+    out: &mut SmallVec<[Component<I>; 4]>,
+) {
+    ty.visit_with(&mut OutlivesCollector { tcx, out, visited: Default::default() });
+}
+
+struct OutlivesCollector<'a, I: Interner> {
+    tcx: I,
+    out: &'a mut SmallVec<[Component<I>; 4]>,
+    visited: SsoHashSet<I::Ty>,
+}
+
+impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
+    fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
+        if !self.visited.insert(ty) {
+            return;
+        }
+        // Descend through the types, looking for the various "base"
+        // components and collecting them into `out`. This is not written
+        // with `collect()` because of the need to sometimes skip subtrees
+        // in the `subtys` iterator (e.g., when encountering a
+        // projection).
+        match ty.kind() {
+            ty::FnDef(_, args) => {
+                // HACK(eddyb) ignore lifetimes found shallowly in `args`.
+                // This is inconsistent with `ty::Adt` (including all args)
+                // and with `ty::Closure` (ignoring all args other than
+                // upvars, of which a `ty::FnDef` doesn't have any), but
+                // consistent with previous (accidental) behavior.
+                // See https://github.com/rust-lang/rust/issues/70917
+                // for further background and discussion.
+                for child in args.iter() {
+                    match child.kind() {
+                        ty::GenericArgKind::Lifetime(_) => {}
+                        ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) => {
+                            child.visit_with(self);
+                        }
+                    }
+                }
+            }
+
+            ty::Closure(_, args) => {
+                args.as_closure().tupled_upvars_ty().visit_with(self);
+            }
+
+            ty::CoroutineClosure(_, args) => {
+                args.as_coroutine_closure().tupled_upvars_ty().visit_with(self);
+            }
+
+            ty::Coroutine(_, args) => {
+                args.as_coroutine().tupled_upvars_ty().visit_with(self);
+
+                // We ignore regions in the coroutine interior as we don't
+                // want these to affect region inference
+            }
+
+            // All regions are bound inside a witness, and we don't emit
+            // higher-ranked outlives components currently.
+            ty::CoroutineWitness(..) => {}
+
+            // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
+            // is implied by the environment is done in regionck.
+            ty::Param(p) => {
+                self.out.push(Component::Param(p));
+            }
+
+            ty::Placeholder(p) => {
+                self.out.push(Component::Placeholder(p));
+            }
+
+            // For projections, we prefer to generate an obligation like
+            // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
+            // regionck more ways to prove that it holds. However,
+            // regionck is not (at least currently) prepared to deal with
+            // higher-ranked regions that may appear in the
+            // trait-ref. Therefore, if we see any higher-ranked regions,
+            // we simply fallback to the most restrictive rule, which
+            // requires that `Pi: 'a` for all `i`.
+            ty::Alias(_, alias_ty) => {
+                if !alias_ty.has_escaping_bound_vars() {
+                    // best case: no escaping regions, so push the
+                    // projection and skip the subtree (thus generating no
+                    // constraints for Pi). This defers the choice between
+                    // the rules OutlivesProjectionEnv,
+                    // OutlivesProjectionTraitDef, and
+                    // OutlivesProjectionComponents to regionck.
+                    self.out.push(Component::Alias(alias_ty));
+                } else {
+                    // fallback case: hard code
+                    // OutlivesProjectionComponents. Continue walking
+                    // through and constrain Pi.
+                    let mut subcomponents = smallvec![];
+                    compute_alias_components_recursive(self.tcx, ty, &mut subcomponents);
+                    self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
+                }
+            }
+
+            // We assume that inference variables are fully resolved.
+            // So, if we encounter an inference variable, just record
+            // the unresolved variable as a component.
+            ty::Infer(infer_ty) => {
+                self.out.push(Component::UnresolvedInferenceVariable(infer_ty));
+            }
+
+            // Most types do not introduce any region binders, nor
+            // involve any other subtle cases, and so the WF relation
+            // simply constraints any regions referenced directly by
+            // the type and then visits the types that are lexically
+            // contained within.
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Str
+            | ty::Never
+            | ty::Error(_) => {
+                // Trivial
+            }
+
+            ty::Bound(_, _) => {
+                // FIXME: Bound vars matter here!
+            }
+
+            ty::Adt(_, _)
+            | ty::Foreign(_)
+            | ty::Array(_, _)
+            | ty::Pat(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_, _)
+            | ty::Ref(_, _, _)
+            | ty::FnPtr(_)
+            | ty::Dynamic(_, _, _)
+            | ty::Tuple(_) => {
+                ty.super_visit_with(self);
+            }
+        }
+    }
+
+    fn visit_region(&mut self, lt: I::Region) -> Self::Result {
+        if !lt.is_bound() {
+            self.out.push(Component::Region(lt));
+        }
+    }
+}
+
+/// Collect [Component]s for *all* the args of `parent`.
+///
+/// This should not be used to get the components of `parent` itself.
+/// Use [push_outlives_components] instead.
+pub fn compute_alias_components_recursive<I: Interner>(
+    tcx: I,
+    alias_ty: I::Ty,
+    out: &mut SmallVec<[Component<I>; 4]>,
+) {
+    let ty::Alias(kind, alias_ty) = alias_ty.kind() else {
+        unreachable!("can only call `compute_alias_components_recursive` on an alias type")
+    };
+
+    let opt_variances =
+        if kind == ty::Opaque { Some(tcx.variances_of(alias_ty.def_id)) } else { None };
+
+    let mut visitor = OutlivesCollector { tcx, out, visited: Default::default() };
+
+    for (index, child) in alias_ty.args.iter().enumerate() {
+        if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) {
+            continue;
+        }
+        child.visit_with(&mut visitor);
+    }
+}
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 1ec095a46f7..65bcb241e4a 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -2374,7 +2374,7 @@ impl dyn Error + Send {
         let err: Box<dyn Error> = self;
         <dyn Error>::downcast(err).map_err(|s| unsafe {
             // Reapply the `Send` marker.
-            Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send))
+            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
         })
     }
 }
@@ -2387,8 +2387,8 @@ impl dyn Error + Send + Sync {
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
         let err: Box<dyn Error> = self;
         <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // Reapply the `Send + Sync` marker.
-            Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send + Sync))
+            // Reapply the `Send + Sync` markers.
+            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
         })
     }
 }
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index 56620cf890d..ba1f38dcc3e 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -1796,18 +1796,18 @@ fn test_ord_absence() {
     }
 
     fn map_debug<K: Debug>(mut map: BTreeMap<K, ()>) {
-        format!("{map:?}");
-        format!("{:?}", map.iter());
-        format!("{:?}", map.iter_mut());
-        format!("{:?}", map.keys());
-        format!("{:?}", map.values());
-        format!("{:?}", map.values_mut());
+        let _ = format!("{map:?}");
+        let _ = format!("{:?}", map.iter());
+        let _ = format!("{:?}", map.iter_mut());
+        let _ = format!("{:?}", map.keys());
+        let _ = format!("{:?}", map.values());
+        let _ = format!("{:?}", map.values_mut());
         if true {
-            format!("{:?}", map.into_iter());
+            let _ = format!("{:?}", map.into_iter());
         } else if true {
-            format!("{:?}", map.into_keys());
+            let _ = format!("{:?}", map.into_keys());
         } else {
-            format!("{:?}", map.into_values());
+            let _ = format!("{:?}", map.into_values());
         }
     }
 
diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs
index 688ce57e9da..48bf7674138 100644
--- a/library/alloc/src/collections/btree/set/tests.rs
+++ b/library/alloc/src/collections/btree/set/tests.rs
@@ -705,9 +705,9 @@ fn test_ord_absence() {
     }
 
     fn set_debug<K: Debug>(set: BTreeSet<K>) {
-        format!("{set:?}");
-        format!("{:?}", set.iter());
-        format!("{:?}", set.into_iter());
+        let _ = format!("{set:?}");
+        let _ = format!("{:?}", set.iter());
+        let _ = format!("{:?}", set.into_iter());
     }
 
     fn set_clone<K: Clone>(mut set: BTreeSet<K>) {
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index 01510a61405..077483a174b 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -1495,6 +1495,14 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> {
     pub fn back(&self) -> Option<&'a T> {
         self.list.back()
     }
+
+    /// Provides a reference to the cursor's parent list.
+    #[must_use]
+    #[inline(always)]
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn as_list(&self) -> &'a LinkedList<T, A> {
+        self.list
+    }
 }
 
 impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
@@ -1605,6 +1613,18 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
     pub fn as_cursor(&self) -> Cursor<'_, T, A> {
         Cursor { list: self.list, current: self.current, index: self.index }
     }
+
+    /// Provides a read-only reference to the cursor's parent list.
+    ///
+    /// The lifetime of the returned reference is bound to that of the
+    /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the
+    /// `CursorMut` is frozen for the lifetime of the reference.
+    #[must_use]
+    #[inline(always)]
+    #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    pub fn as_list(&self) -> &LinkedList<T, A> {
+        self.list
+    }
 }
 
 // Now the list editing operations
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 61d05afccfd..a07f250d7d8 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -164,6 +164,20 @@ impl<T, A: Allocator> VecDeque<T, A> {
         self.buf.ptr()
     }
 
+    /// Appends an element to the buffer.
+    ///
+    /// # Safety
+    ///
+    /// May only be called if `deque.len() < deque.capacity()`
+    #[inline]
+    unsafe fn push_unchecked(&mut self, element: T) {
+        // SAFETY: Because of the precondition, it's guaranteed that there is space
+        // in the logical array after the last element.
+        unsafe { self.buffer_write(self.to_physical_idx(self.len), element) };
+        // This can't overflow because `deque.len() < deque.capacity() <= usize::MAX`.
+        self.len += 1;
+    }
+
     /// Moves an element out of the buffer
     #[inline]
     unsafe fn buffer_read(&mut self, off: usize) -> T {
@@ -2911,6 +2925,14 @@ impl<T, A: Allocator> Extend<T> for VecDeque<T, A> {
     fn extend_reserve(&mut self, additional: usize) {
         self.reserve(additional);
     }
+
+    #[inline]
+    unsafe fn extend_one_unchecked(&mut self, item: T) {
+        // SAFETY: Our preconditions ensure the space has been reserved, and `extend_reserve` is implemented correctly.
+        unsafe {
+            self.push_unchecked(item);
+        }
+    }
 }
 
 #[stable(feature = "extend_ref", since = "1.2.0")]
@@ -2928,6 +2950,14 @@ impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque<T, A> {
     fn extend_reserve(&mut self, additional: usize) {
         self.reserve(additional);
     }
+
+    #[inline]
+    unsafe fn extend_one_unchecked(&mut self, &item: &'a T) {
+        // SAFETY: Our preconditions ensure the space has been reserved, and `extend_reserve` is implemented correctly.
+        unsafe {
+            self.push_unchecked(item);
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs
index dccf40ccb38..6a89abc3ef9 100644
--- a/library/alloc/src/collections/vec_deque/spec_extend.rs
+++ b/library/alloc/src/collections/vec_deque/spec_extend.rs
@@ -21,21 +21,12 @@ where
         //     self.push_back(item);
         // }
 
-        // May only be called if `deque.len() < deque.capacity()`
-        unsafe fn push_unchecked<T, A: Allocator>(deque: &mut VecDeque<T, A>, element: T) {
-            // SAFETY: Because of the precondition, it's guaranteed that there is space
-            // in the logical array after the last element.
-            unsafe { deque.buffer_write(deque.to_physical_idx(deque.len), element) };
-            // This can't overflow because `deque.len() < deque.capacity() <= usize::MAX`.
-            deque.len += 1;
-        }
-
         while let Some(element) = iter.next() {
             let (lower, _) = iter.size_hint();
             self.reserve(lower.saturating_add(1));
 
             // SAFETY: We just reserved space for at least one element.
-            unsafe { push_unchecked(self, element) };
+            unsafe { self.push_unchecked(element) };
 
             // Inner loop to avoid repeatedly calling `reserve`.
             while self.len < self.capacity() {
@@ -43,7 +34,7 @@ where
                     return;
                 };
                 // SAFETY: The loop condition guarantees that `self.len() < self.capacity()`.
-                unsafe { push_unchecked(self, element) };
+                unsafe { self.push_unchecked(element) };
             }
         }
     }
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index ae44cab8131..c6bba619ae6 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -12,6 +12,7 @@
 //! Some examples of the [`format!`] extension are:
 //!
 //! ```
+//! # #![allow(unused_must_use)]
 //! format!("Hello");                 // => "Hello"
 //! format!("Hello, {}!", "world");   // => "Hello, world!"
 //! format!("The number is {}", 1);   // => "The number is 1"
@@ -50,6 +51,7 @@
 //! the iterator advances. This leads to behavior like this:
 //!
 //! ```
+//! # #![allow(unused_must_use)]
 //! format!("{1} {} {0} {}", 1, 2); // => "2 1 1 2"
 //! ```
 //!
@@ -77,6 +79,7 @@
 //! For example, the following [`format!`] expressions all use named arguments:
 //!
 //! ```
+//! # #![allow(unused_must_use)]
 //! format!("{argument}", argument = "test");   // => "test"
 //! format!("{name} {}", 1, name = 2);          // => "2 1"
 //! format!("{a} {c} {b}", a="a", b='b', c=3);  // => "a 3 b"
@@ -86,6 +89,7 @@
 //! reference a variable with that name in the current scope.
 //!
 //! ```
+//! # #![allow(unused_must_use)]
 //! let argument = 2 + 2;
 //! format!("{argument}");   // => "4"
 //!
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index a1a2404a2ee..a7715740cbd 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -124,10 +124,10 @@
 #![feature(error_generic_member_access)]
 #![feature(exact_size_is_empty)]
 #![feature(extend_one)]
+#![feature(extend_one_unchecked)]
 #![feature(fmt_internals)]
 #![feature(fn_traits)]
 #![feature(hasher_prefixfree_extras)]
-#![feature(hint_assert_unchecked)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
 #![feature(iter_next_chunk)]
@@ -257,6 +257,7 @@ pub mod vec;
 #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
 pub mod __export {
     pub use core::format_args;
+    pub use core::hint::must_use;
 }
 
 #[cfg(test)]
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index d5ca5c4ed27..8c6a367869c 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -111,6 +111,7 @@ macro_rules! vec {
 /// # Examples
 ///
 /// ```
+/// # #![allow(unused_must_use)]
 /// format!("test");                             // => "test"
 /// format!("hello {}", "world!");               // => "hello world!"
 /// format!("x = {}, y = {val}", 10, val = 30);  // => "x = 10, y = 30"
@@ -119,10 +120,13 @@ macro_rules! vec {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[allow_internal_unstable(hint_must_use, liballoc_internals)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")]
 macro_rules! format {
-    ($($arg:tt)*) => {{
-        let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
-        res
-    }}
+    ($($arg:tt)*) => {
+        $crate::__export::must_use({
+            let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
+            res
+        })
+    }
 }
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 1134c7f833e..7b7dae5a057 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -429,6 +429,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     ///
     /// Aborts on OOM.
     #[cfg(not(no_global_oom_handling))]
+    #[inline]
     pub fn shrink_to_fit(&mut self, cap: usize) {
         if let Err(err) = self.shrink(cap) {
             handle_error(err);
@@ -511,9 +512,25 @@ impl<T, A: Allocator> RawVec<T, A> {
     }
 
     #[cfg(not(no_global_oom_handling))]
+    #[inline]
     fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> {
         assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity");
+        // SAFETY: Just checked this isn't trying to grow
+        unsafe { self.shrink_unchecked(cap) }
+    }
 
+    /// `shrink`, but without the capacity check.
+    ///
+    /// This is split out so that `shrink` can inline the check, since it
+    /// optimizes out in things like `shrink_to_fit`, without needing to
+    /// also inline all this code, as doing that ends up failing the
+    /// `vec-shrink-panic` codegen test when `shrink_to_fit` ends up being too
+    /// big for LLVM to be willing to inline.
+    ///
+    /// # Safety
+    /// `cap <= self.capacity()`
+    #[cfg(not(no_global_oom_handling))]
+    unsafe fn shrink_unchecked(&mut self, cap: usize) -> Result<(), TryReserveError> {
         let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
         // See current_memory() why this assert is here
         const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 90672164cb9..1983ea8281a 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -197,11 +197,7 @@ macro_rules! acquire {
 ///
 /// Sharing some immutable data between threads:
 ///
-// Note that we **do not** run these tests here. The windows builders get super
-// unhappy if a thread outlives the main thread and then exits at the same time
-// (something deadlocks) so we just avoid this entirely by not running these
-// tests.
-/// ```no_run
+/// ```
 /// use std::sync::Arc;
 /// use std::thread;
 ///
@@ -220,7 +216,7 @@ macro_rules! acquire {
 ///
 /// [`AtomicUsize`]: core::sync::atomic::AtomicUsize "sync::atomic::AtomicUsize"
 ///
-/// ```no_run
+/// ```
 /// use std::sync::Arc;
 /// use std::sync::atomic::{AtomicUsize, Ordering};
 /// use std::thread;
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 743429d26db..6e9b017ad75 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1101,6 +1101,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline]
     pub fn shrink_to_fit(&mut self) {
         // The capacity is never less than the length, and there's nothing to do when
         // they are equal, so we can avoid the panic case in `RawVec::shrink_to_fit`
@@ -3047,6 +3048,16 @@ impl<T, A: Allocator> Extend<T> for Vec<T, A> {
     fn extend_reserve(&mut self, additional: usize) {
         self.reserve(additional);
     }
+
+    #[inline]
+    unsafe fn extend_one_unchecked(&mut self, item: T) {
+        // SAFETY: Our preconditions ensure the space has been reserved, and `extend_reserve` is implemented correctly.
+        unsafe {
+            let len = self.len();
+            ptr::write(self.as_mut_ptr().add(len), item);
+            self.set_len(len + 1);
+        }
+    }
 }
 
 impl<T, A: Allocator> Vec<T, A> {
@@ -3243,6 +3254,16 @@ impl<'a, T: Copy + 'a, A: Allocator> Extend<&'a T> for Vec<T, A> {
     fn extend_reserve(&mut self, additional: usize) {
         self.reserve(additional);
     }
+
+    #[inline]
+    unsafe fn extend_one_unchecked(&mut self, &item: &'a T) {
+        // SAFETY: Our preconditions ensure the space has been reserved, and `extend_reserve` is implemented correctly.
+        unsafe {
+            let len = self.len();
+            ptr::write(self.as_mut_ptr().add(len), item);
+            self.set_len(len + 1);
+        }
+    }
 }
 
 /// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison).
diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs
index 379e09ab69a..ce24a40f4c0 100644
--- a/library/alloc/tests/fmt.rs
+++ b/library/alloc/tests/fmt.rs
@@ -217,19 +217,19 @@ fn test_format_macro_interface() {
 
     // make sure that format! doesn't move out of local variables
     let a = Box::new(3);
-    format!("{a}");
-    format!("{a}");
+    let _ = format!("{a}");
+    let _ = format!("{a}");
 
     // make sure that format! doesn't cause spurious unused-unsafe warnings when
     // it's inside of an outer unsafe block
     unsafe {
         let a: isize = ::std::mem::transmute(3_usize);
-        format!("{a}");
+        let _ = format!("{a}");
     }
 
     // test that trailing commas are acceptable
-    format!("{}", "test",);
-    format!("{foo}", foo = "test",);
+    let _ = format!("{}", "test",);
+    let _ = format!("{foo}", foo = "test",);
 }
 
 // Basic test to make sure that we can invoke the `write!` macro with an
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index eab11ae288a..59f3b6841d5 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -673,7 +673,7 @@ impl hash::Hash for TypeId {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Debug for TypeId {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
-        f.debug_tuple("TypeId").field(&self.as_u128()).finish()
+        write!(f, "TypeId({:#034x})", self.as_u128())
     }
 }
 
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index d7ce65f6c53..939b2be6dfa 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -230,7 +230,7 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> {
 pub unsafe trait CloneToUninit {
     /// Performs copy-assignment from `self` to `dst`.
     ///
-    /// This is analogous to to `std::ptr::write(dst, self.clone())`,
+    /// This is analogous to `std::ptr::write(dst, self.clone())`,
     /// except that `self` may be a dynamically-sized type ([`!Sized`](Sized)).
     ///
     /// Before this function is called, `dst` may point to uninitialized memory.
diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index 5cacedcb241..4524b352ec8 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -103,7 +103,6 @@ use crate::ascii::Char as AsciiChar;
 /// ```
 #[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
 pub trait Default: Sized {
     /// Returns the "default value" for a type.
     ///
diff --git a/library/core/src/error.rs b/library/core/src/error.rs
index 150e4f3f318..ca8983d4cbc 100644
--- a/library/core/src/error.rs
+++ b/library/core/src/error.rs
@@ -1008,8 +1008,15 @@ impl<'a> Iterator for Source<'a> {
         self.current = self.current.and_then(Error::source);
         current
     }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.current.is_some() { (1, None) } else { (0, Some(0)) }
+    }
 }
 
+#[unstable(feature = "error_iter", issue = "58520")]
+impl<'a> crate::iter::FusedIterator for Source<'a> {}
+
 #[stable(feature = "error_by_ref", since = "1.51.0")]
 impl<'a, T: Error + ?Sized> Error for &'a T {
     #[allow(deprecated, deprecated_in_future)]
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index 6d1f10f5211..88adc378477 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -10,8 +10,6 @@
 #![allow(non_camel_case_types)]
 
 use crate::fmt;
-use crate::marker::PhantomData;
-use crate::ops::{Deref, DerefMut};
 
 #[doc(no_inline)]
 #[stable(feature = "core_c_str", since = "1.64.0")]
@@ -28,6 +26,20 @@ pub use self::c_str::CStr;
 #[unstable(feature = "c_str_module", issue = "112134")]
 pub mod c_str;
 
+#[unstable(
+    feature = "c_variadic",
+    issue = "44930",
+    reason = "the `c_variadic` feature has not been properly tested on all supported platforms"
+)]
+pub use self::va_list::{VaList, VaListImpl};
+
+#[unstable(
+    feature = "c_variadic",
+    issue = "44930",
+    reason = "the `c_variadic` feature has not been properly tested on all supported platforms"
+)]
+pub mod va_list;
+
 macro_rules! type_alias {
     {
       $Docfile:tt, $Alias:ident = $Real:ty;
@@ -205,404 +217,6 @@ impl fmt::Debug for c_void {
     }
 }
 
-/// Basic implementation of a `va_list`.
-// The name is WIP, using `VaListImpl` for now.
-#[cfg(any(
-    all(
-        not(target_arch = "aarch64"),
-        not(target_arch = "powerpc"),
-        not(target_arch = "s390x"),
-        not(target_arch = "x86_64")
-    ),
-    all(target_arch = "aarch64", target_vendor = "apple"),
-    target_family = "wasm",
-    target_os = "uefi",
-    windows,
-))]
-#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-#[lang = "va_list"]
-pub struct VaListImpl<'f> {
-    ptr: *mut c_void,
-
-    // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to
-    // the region of the function it's defined in
-    _marker: PhantomData<&'f mut &'f c_void>,
-}
-
-#[cfg(any(
-    all(
-        not(target_arch = "aarch64"),
-        not(target_arch = "powerpc"),
-        not(target_arch = "s390x"),
-        not(target_arch = "x86_64")
-    ),
-    all(target_arch = "aarch64", target_vendor = "apple"),
-    target_family = "wasm",
-    target_os = "uefi",
-    windows,
-))]
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-impl<'f> fmt::Debug for VaListImpl<'f> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "va_list* {:p}", self.ptr)
-    }
-}
-
-/// AArch64 ABI implementation of a `va_list`. See the
-/// [AArch64 Procedure Call Standard] for more details.
-///
-/// [AArch64 Procedure Call Standard]:
-/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
-#[cfg(all(
-    target_arch = "aarch64",
-    not(target_vendor = "apple"),
-    not(target_os = "uefi"),
-    not(windows),
-))]
-#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
-#[derive(Debug)]
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-#[lang = "va_list"]
-pub struct VaListImpl<'f> {
-    stack: *mut c_void,
-    gr_top: *mut c_void,
-    vr_top: *mut c_void,
-    gr_offs: i32,
-    vr_offs: i32,
-    _marker: PhantomData<&'f mut &'f c_void>,
-}
-
-/// PowerPC ABI implementation of a `va_list`.
-#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))]
-#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
-#[derive(Debug)]
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-#[lang = "va_list"]
-pub struct VaListImpl<'f> {
-    gpr: u8,
-    fpr: u8,
-    reserved: u16,
-    overflow_arg_area: *mut c_void,
-    reg_save_area: *mut c_void,
-    _marker: PhantomData<&'f mut &'f c_void>,
-}
-
-/// s390x ABI implementation of a `va_list`.
-#[cfg(target_arch = "s390x")]
-#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
-#[derive(Debug)]
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-#[lang = "va_list"]
-pub struct VaListImpl<'f> {
-    gpr: i64,
-    fpr: i64,
-    overflow_arg_area: *mut c_void,
-    reg_save_area: *mut c_void,
-    _marker: PhantomData<&'f mut &'f c_void>,
-}
-
-/// x86_64 ABI implementation of a `va_list`.
-#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))]
-#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
-#[derive(Debug)]
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-#[lang = "va_list"]
-pub struct VaListImpl<'f> {
-    gp_offset: i32,
-    fp_offset: i32,
-    overflow_arg_area: *mut c_void,
-    reg_save_area: *mut c_void,
-    _marker: PhantomData<&'f mut &'f c_void>,
-}
-
-/// A wrapper for a `va_list`
-#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
-#[derive(Debug)]
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-pub struct VaList<'a, 'f: 'a> {
-    #[cfg(any(
-        all(
-            not(target_arch = "aarch64"),
-            not(target_arch = "powerpc"),
-            not(target_arch = "s390x"),
-            not(target_arch = "x86_64")
-        ),
-        all(target_arch = "aarch64", target_vendor = "apple"),
-        target_family = "wasm",
-        target_os = "uefi",
-        windows,
-    ))]
-    inner: VaListImpl<'f>,
-
-    #[cfg(all(
-        any(
-            target_arch = "aarch64",
-            target_arch = "powerpc",
-            target_arch = "s390x",
-            target_arch = "x86_64"
-        ),
-        any(not(target_arch = "aarch64"), not(target_vendor = "apple")),
-        not(target_family = "wasm"),
-        not(target_os = "uefi"),
-        not(windows),
-    ))]
-    inner: &'a mut VaListImpl<'f>,
-
-    _marker: PhantomData<&'a mut VaListImpl<'f>>,
-}
-
-#[cfg(any(
-    all(
-        not(target_arch = "aarch64"),
-        not(target_arch = "powerpc"),
-        not(target_arch = "s390x"),
-        not(target_arch = "x86_64")
-    ),
-    all(target_arch = "aarch64", target_vendor = "apple"),
-    target_family = "wasm",
-    target_os = "uefi",
-    windows,
-))]
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-impl<'f> VaListImpl<'f> {
-    /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
-    #[inline]
-    pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
-        VaList { inner: VaListImpl { ..*self }, _marker: PhantomData }
-    }
-}
-
-#[cfg(all(
-    any(
-        target_arch = "aarch64",
-        target_arch = "powerpc",
-        target_arch = "s390x",
-        target_arch = "x86_64"
-    ),
-    any(not(target_arch = "aarch64"), not(target_vendor = "apple")),
-    not(target_family = "wasm"),
-    not(target_os = "uefi"),
-    not(windows),
-))]
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-impl<'f> VaListImpl<'f> {
-    /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
-    #[inline]
-    pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
-        VaList { inner: self, _marker: PhantomData }
-    }
-}
-
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-impl<'a, 'f: 'a> Deref for VaList<'a, 'f> {
-    type Target = VaListImpl<'f>;
-
-    #[inline]
-    fn deref(&self) -> &VaListImpl<'f> {
-        &self.inner
-    }
-}
-
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
-    #[inline]
-    fn deref_mut(&mut self) -> &mut VaListImpl<'f> {
-        &mut self.inner
-    }
-}
-
-// The VaArgSafe trait needs to be used in public interfaces, however, the trait
-// itself must not be allowed to be used outside this module. Allowing users to
-// implement the trait for a new type (thereby allowing the va_arg intrinsic to
-// be used on a new type) is likely to cause undefined behavior.
-//
-// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
-// but also ensure it cannot be used elsewhere, the trait needs to be public
-// within a private module. Once RFC 2145 has been implemented look into
-// improving this.
-mod sealed_trait {
-    /// Trait which permits the allowed types to be used with [super::VaListImpl::arg].
-    #[unstable(
-        feature = "c_variadic",
-        reason = "the `c_variadic` feature has not been properly tested on \
-                  all supported platforms",
-        issue = "44930"
-    )]
-    pub unsafe trait VaArgSafe {}
-}
-
-macro_rules! impl_va_arg_safe {
-    ($($t:ty),+) => {
-        $(
-            #[unstable(feature = "c_variadic",
-                       reason = "the `c_variadic` feature has not been properly tested on \
-                                 all supported platforms",
-                       issue = "44930")]
-            unsafe impl sealed_trait::VaArgSafe for $t {}
-        )+
-    }
-}
-
-impl_va_arg_safe! {i8, i16, i32, i64, usize}
-impl_va_arg_safe! {u8, u16, u32, u64, isize}
-impl_va_arg_safe! {f64}
-
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-unsafe impl<T> sealed_trait::VaArgSafe for *mut T {}
-
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-unsafe impl<T> sealed_trait::VaArgSafe for *const T {}
-
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-impl<'f> VaListImpl<'f> {
-    /// Advance to the next arg.
-    #[inline]
-    pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
-        // SAFETY: the caller must uphold the safety contract for `va_arg`.
-        unsafe { va_arg(self) }
-    }
-
-    /// Copies the `va_list` at the current location.
-    pub unsafe fn with_copy<F, R>(&self, f: F) -> R
-    where
-        F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R,
-    {
-        let mut ap = self.clone();
-        let ret = f(ap.as_va_list());
-        // SAFETY: the caller must uphold the safety contract for `va_end`.
-        unsafe {
-            va_end(&mut ap);
-        }
-        ret
-    }
-}
-
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-impl<'f> Clone for VaListImpl<'f> {
-    #[inline]
-    fn clone(&self) -> Self {
-        let mut dest = crate::mem::MaybeUninit::uninit();
-        // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal
-        unsafe {
-            va_copy(dest.as_mut_ptr(), self);
-            dest.assume_init()
-        }
-    }
-}
-
-#[unstable(
-    feature = "c_variadic",
-    reason = "the `c_variadic` feature has not been properly tested on \
-              all supported platforms",
-    issue = "44930"
-)]
-impl<'f> Drop for VaListImpl<'f> {
-    fn drop(&mut self) {
-        // FIXME: this should call `va_end`, but there's no clean way to
-        // guarantee that `drop` always gets inlined into its caller,
-        // so the `va_end` would get directly called from the same function as
-        // the corresponding `va_copy`. `man va_end` states that C requires this,
-        // and LLVM basically follows the C semantics, so we need to make sure
-        // that `va_end` is always called from the same function as `va_copy`.
-        // For more details, see https://github.com/rust-lang/rust/pull/59625
-        // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
-        //
-        // This works for now, since `va_end` is a no-op on all current LLVM targets.
-    }
-}
-
-extern "rust-intrinsic" {
-    /// Destroy the arglist `ap` after initialization with `va_start` or
-    /// `va_copy`.
-    #[rustc_nounwind]
-    fn va_end(ap: &mut VaListImpl<'_>);
-
-    /// Copies the current location of arglist `src` to the arglist `dst`.
-    #[rustc_nounwind]
-    fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
-
-    /// Loads an argument of type `T` from the `va_list` `ap` and increment the
-    /// argument `ap` points to.
-    #[rustc_nounwind]
-    fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
-}
-
 // Link the MSVC default lib
 #[cfg(all(windows, target_env = "msvc"))]
 #[link(
diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs
new file mode 100644
index 00000000000..6a2e8b67d0c
--- /dev/null
+++ b/library/core/src/ffi/va_list.rs
@@ -0,0 +1,301 @@
+//! C's "variable arguments"
+//!
+//! Better known as "varargs".
+
+use crate::ffi::c_void;
+
+#[allow(unused_imports)]
+use crate::fmt;
+use crate::marker::PhantomData;
+use crate::ops::{Deref, DerefMut};
+
+/// Basic implementation of a `va_list`.
+// The name is WIP, using `VaListImpl` for now.
+#[cfg(any(
+    all(
+        not(target_arch = "aarch64"),
+        not(target_arch = "powerpc"),
+        not(target_arch = "s390x"),
+        not(target_arch = "x86_64")
+    ),
+    all(target_arch = "aarch64", target_vendor = "apple"),
+    target_family = "wasm",
+    target_os = "uefi",
+    windows,
+))]
+#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
+#[lang = "va_list"]
+pub struct VaListImpl<'f> {
+    ptr: *mut c_void,
+
+    // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to
+    // the region of the function it's defined in
+    _marker: PhantomData<&'f mut &'f c_void>,
+}
+
+#[cfg(any(
+    all(
+        not(target_arch = "aarch64"),
+        not(target_arch = "powerpc"),
+        not(target_arch = "s390x"),
+        not(target_arch = "x86_64")
+    ),
+    all(target_arch = "aarch64", target_vendor = "apple"),
+    target_family = "wasm",
+    target_os = "uefi",
+    windows,
+))]
+impl<'f> fmt::Debug for VaListImpl<'f> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "va_list* {:p}", self.ptr)
+    }
+}
+
+/// AArch64 ABI implementation of a `va_list`. See the
+/// [AArch64 Procedure Call Standard] for more details.
+///
+/// [AArch64 Procedure Call Standard]:
+/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
+#[cfg(all(
+    target_arch = "aarch64",
+    not(target_vendor = "apple"),
+    not(target_os = "uefi"),
+    not(windows),
+))]
+#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
+#[derive(Debug)]
+#[lang = "va_list"]
+pub struct VaListImpl<'f> {
+    stack: *mut c_void,
+    gr_top: *mut c_void,
+    vr_top: *mut c_void,
+    gr_offs: i32,
+    vr_offs: i32,
+    _marker: PhantomData<&'f mut &'f c_void>,
+}
+
+/// PowerPC ABI implementation of a `va_list`.
+#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))]
+#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
+#[derive(Debug)]
+#[lang = "va_list"]
+pub struct VaListImpl<'f> {
+    gpr: u8,
+    fpr: u8,
+    reserved: u16,
+    overflow_arg_area: *mut c_void,
+    reg_save_area: *mut c_void,
+    _marker: PhantomData<&'f mut &'f c_void>,
+}
+
+/// s390x ABI implementation of a `va_list`.
+#[cfg(target_arch = "s390x")]
+#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
+#[derive(Debug)]
+#[lang = "va_list"]
+pub struct VaListImpl<'f> {
+    gpr: i64,
+    fpr: i64,
+    overflow_arg_area: *mut c_void,
+    reg_save_area: *mut c_void,
+    _marker: PhantomData<&'f mut &'f c_void>,
+}
+
+/// x86_64 ABI implementation of a `va_list`.
+#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))]
+#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401
+#[derive(Debug)]
+#[lang = "va_list"]
+pub struct VaListImpl<'f> {
+    gp_offset: i32,
+    fp_offset: i32,
+    overflow_arg_area: *mut c_void,
+    reg_save_area: *mut c_void,
+    _marker: PhantomData<&'f mut &'f c_void>,
+}
+
+/// A wrapper for a `va_list`
+#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
+#[derive(Debug)]
+pub struct VaList<'a, 'f: 'a> {
+    #[cfg(any(
+        all(
+            not(target_arch = "aarch64"),
+            not(target_arch = "powerpc"),
+            not(target_arch = "s390x"),
+            not(target_arch = "x86_64")
+        ),
+        all(target_arch = "aarch64", target_vendor = "apple"),
+        target_family = "wasm",
+        target_os = "uefi",
+        windows,
+    ))]
+    inner: VaListImpl<'f>,
+
+    #[cfg(all(
+        any(
+            target_arch = "aarch64",
+            target_arch = "powerpc",
+            target_arch = "s390x",
+            target_arch = "x86_64"
+        ),
+        any(not(target_arch = "aarch64"), not(target_vendor = "apple")),
+        not(target_family = "wasm"),
+        not(target_os = "uefi"),
+        not(windows),
+    ))]
+    inner: &'a mut VaListImpl<'f>,
+
+    _marker: PhantomData<&'a mut VaListImpl<'f>>,
+}
+
+#[cfg(any(
+    all(
+        not(target_arch = "aarch64"),
+        not(target_arch = "powerpc"),
+        not(target_arch = "s390x"),
+        not(target_arch = "x86_64")
+    ),
+    all(target_arch = "aarch64", target_vendor = "apple"),
+    target_family = "wasm",
+    target_os = "uefi",
+    windows,
+))]
+impl<'f> VaListImpl<'f> {
+    /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
+    #[inline]
+    pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
+        VaList { inner: VaListImpl { ..*self }, _marker: PhantomData }
+    }
+}
+
+#[cfg(all(
+    any(
+        target_arch = "aarch64",
+        target_arch = "powerpc",
+        target_arch = "s390x",
+        target_arch = "x86_64"
+    ),
+    any(not(target_arch = "aarch64"), not(target_vendor = "apple")),
+    not(target_family = "wasm"),
+    not(target_os = "uefi"),
+    not(windows),
+))]
+impl<'f> VaListImpl<'f> {
+    /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
+    #[inline]
+    pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
+        VaList { inner: self, _marker: PhantomData }
+    }
+}
+
+impl<'a, 'f: 'a> Deref for VaList<'a, 'f> {
+    type Target = VaListImpl<'f>;
+
+    #[inline]
+    fn deref(&self) -> &VaListImpl<'f> {
+        &self.inner
+    }
+}
+
+impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut VaListImpl<'f> {
+        &mut self.inner
+    }
+}
+
+// The VaArgSafe trait needs to be used in public interfaces, however, the trait
+// itself must not be allowed to be used outside this module. Allowing users to
+// implement the trait for a new type (thereby allowing the va_arg intrinsic to
+// be used on a new type) is likely to cause undefined behavior.
+//
+// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
+// but also ensure it cannot be used elsewhere, the trait needs to be public
+// within a private module. Once RFC 2145 has been implemented look into
+// improving this.
+mod sealed_trait {
+    /// Trait which permits the allowed types to be used with [super::VaListImpl::arg].
+    pub unsafe trait VaArgSafe {}
+}
+
+macro_rules! impl_va_arg_safe {
+    ($($t:ty),+) => {
+        $(
+            unsafe impl sealed_trait::VaArgSafe for $t {}
+        )+
+    }
+}
+
+impl_va_arg_safe! {i8, i16, i32, i64, usize}
+impl_va_arg_safe! {u8, u16, u32, u64, isize}
+impl_va_arg_safe! {f64}
+
+unsafe impl<T> sealed_trait::VaArgSafe for *mut T {}
+unsafe impl<T> sealed_trait::VaArgSafe for *const T {}
+
+impl<'f> VaListImpl<'f> {
+    /// Advance to the next arg.
+    #[inline]
+    pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
+        // SAFETY: the caller must uphold the safety contract for `va_arg`.
+        unsafe { va_arg(self) }
+    }
+
+    /// Copies the `va_list` at the current location.
+    pub unsafe fn with_copy<F, R>(&self, f: F) -> R
+    where
+        F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R,
+    {
+        let mut ap = self.clone();
+        let ret = f(ap.as_va_list());
+        // SAFETY: the caller must uphold the safety contract for `va_end`.
+        unsafe {
+            va_end(&mut ap);
+        }
+        ret
+    }
+}
+
+impl<'f> Clone for VaListImpl<'f> {
+    #[inline]
+    fn clone(&self) -> Self {
+        let mut dest = crate::mem::MaybeUninit::uninit();
+        // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal
+        unsafe {
+            va_copy(dest.as_mut_ptr(), self);
+            dest.assume_init()
+        }
+    }
+}
+
+impl<'f> Drop for VaListImpl<'f> {
+    fn drop(&mut self) {
+        // FIXME: this should call `va_end`, but there's no clean way to
+        // guarantee that `drop` always gets inlined into its caller,
+        // so the `va_end` would get directly called from the same function as
+        // the corresponding `va_copy`. `man va_end` states that C requires this,
+        // and LLVM basically follows the C semantics, so we need to make sure
+        // that `va_end` is always called from the same function as `va_copy`.
+        // For more details, see https://github.com/rust-lang/rust/pull/59625
+        // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
+        //
+        // This works for now, since `va_end` is a no-op on all current LLVM targets.
+    }
+}
+
+extern "rust-intrinsic" {
+    /// Destroy the arglist `ap` after initialization with `va_start` or
+    /// `va_copy`.
+    #[rustc_nounwind]
+    fn va_end(ap: &mut VaListImpl<'_>);
+
+    /// Copies the current location of arglist `src` to the arglist `dst`.
+    #[rustc_nounwind]
+    fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
+
+    /// Loads an argument of type `T` from the `va_list` `ap` and increment the
+    /// argument `ap` points to.
+    #[rustc_nounwind]
+    fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
+}
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index d0e188dfcd1..25ab5b2db96 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -517,7 +517,10 @@ impl Display for Arguments<'_> {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
+/// assert_eq!(
+///     format!("The origin is: {origin:?}"),
+///     "The origin is: Point { x: 0, y: 0 }",
+/// );
 /// ```
 ///
 /// Manually implementing:
@@ -541,7 +544,10 @@ impl Display for Arguments<'_> {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
+/// assert_eq!(
+///     format!("The origin is: {origin:?}"),
+///     "The origin is: Point { x: 0, y: 0 }",
+/// );
 /// ```
 ///
 /// There are a number of helper methods on the [`Formatter`] struct to help you with manual
@@ -582,11 +588,11 @@ impl Display for Arguments<'_> {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {origin:#?}"),
-/// "The origin is: Point {
+/// let expected = "The origin is: Point {
 ///     x: 0,
 ///     y: 0,
-/// }");
+/// }";
+/// assert_eq!(format!("The origin is: {origin:#?}"), expected);
 /// ```
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -738,8 +744,10 @@ pub trait Display {
     ///     }
     /// }
     ///
-    /// assert_eq!("(1.987, 2.983)",
-    ///            format!("{}", Position { longitude: 1.987, latitude: 2.983, }));
+    /// assert_eq!(
+    ///     "(1.987, 2.983)",
+    ///     format!("{}", Position { longitude: 1.987, latitude: 2.983, }),
+    /// );
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs
index 78a232faaf8..0d1ac64aa56 100644
--- a/library/core/src/hash/sip.rs
+++ b/library/core/src/hash/sip.rs
@@ -76,18 +76,19 @@ macro_rules! compress {
     ($state:expr) => {{ compress!($state.v0, $state.v1, $state.v2, $state.v3) }};
     ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{
         $v0 = $v0.wrapping_add($v1);
+        $v2 = $v2.wrapping_add($v3);
         $v1 = $v1.rotate_left(13);
         $v1 ^= $v0;
-        $v0 = $v0.rotate_left(32);
-        $v2 = $v2.wrapping_add($v3);
         $v3 = $v3.rotate_left(16);
         $v3 ^= $v2;
-        $v0 = $v0.wrapping_add($v3);
-        $v3 = $v3.rotate_left(21);
-        $v3 ^= $v0;
+        $v0 = $v0.rotate_left(32);
+
         $v2 = $v2.wrapping_add($v1);
+        $v0 = $v0.wrapping_add($v3);
         $v1 = $v1.rotate_left(17);
         $v1 ^= $v2;
+        $v3 = $v3.rotate_left(21);
+        $v3 ^= $v0;
         $v2 = $v2.rotate_left(32);
     }};
 }
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index c3b16c34293..b3e36e6fbc4 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -111,41 +111,92 @@ pub const unsafe fn unreachable_unchecked() -> ! {
 
 /// Makes a *soundness* promise to the compiler that `cond` holds.
 ///
-/// This may allow the optimizer to simplify things,
-/// but it might also make the generated code slower.
-/// Either way, calling it will most likely make compilation take longer.
+/// This may allow the optimizer to simplify things, but it might also make the generated code
+/// slower. Either way, calling it will most likely make compilation take longer.
 ///
-/// This is a situational tool for micro-optimization, and is allowed to do nothing.
-/// Any use should come with a repeatable benchmark to show the value
-/// and allow removing it later should the optimizer get smarter and no longer need it.
+/// You may know this from other places as
+/// [`llvm.assume`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic) or, in C,
+/// [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume).
 ///
-/// The more complicated the condition the less likely this is to be fruitful.
-/// For example, `assert_unchecked(foo.is_sorted())` is a complex enough value
-/// that the compiler is unlikely to be able to take advantage of it.
+/// This promotes a correctness requirement to a soundness requirement. Don't do that without
+/// very good reason.
 ///
-/// There's also no need to `assert_unchecked` basic properties of things.  For
-/// example, the compiler already knows the range of `count_ones`, so there's no
-/// benefit to `let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);`.
+/// # Usage
 ///
-/// If ever you're tempted to write `assert_unchecked(false)`, then you're
-/// actually looking for [`unreachable_unchecked()`].
+/// This is a situational tool for micro-optimization, and is allowed to do nothing. Any use
+/// should come with a repeatable benchmark to show the value, with the expectation to drop it
+/// later should the optimizer get smarter and no longer need it.
 ///
-/// You may know this from other places
-/// as [`llvm.assume`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic)
-/// or [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume).
+/// The more complicated the condition, the less likely this is to be useful. For example,
+/// `assert_unchecked(foo.is_sorted())` is a complex enough value that the compiler is unlikely
+/// to be able to take advantage of it.
 ///
-/// This promotes a correctness requirement to a soundness requirement.
-/// Don't do that without very good reason.
+/// There's also no need to `assert_unchecked` basic properties of things.  For example, the
+/// compiler already knows the range of `count_ones`, so there is no benefit to
+/// `let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);`.
+///
+/// `assert_unchecked` is logically equivalent to `if !cond { unreachable_unchecked(); }`. If
+/// ever you are tempted to write `assert_unchecked(false)`, you should instead use
+/// [`unreachable_unchecked()`] directly.
 ///
 /// # Safety
 ///
-/// `cond` must be `true`.  It's immediate UB to call this with `false`.
+/// `cond` must be `true`. It is immediate UB to call this with `false`.
+///
+/// # Example
+///
+/// ```
+/// use core::hint;
 ///
+/// /// # Safety
+/// ///
+/// /// `p` must be nonnull and valid
+/// pub unsafe fn next_value(p: *const i32) -> i32 {
+///     // SAFETY: caller invariants guarantee that `p` is not null
+///     unsafe { hint::assert_unchecked(!p.is_null()) }
+///
+///     if p.is_null() {
+///         return -1;
+///     } else {
+///         // SAFETY: caller invariants guarantee that `p` is valid
+///         unsafe { *p + 1 }
+///     }
+/// }
+/// ```
+///
+/// Without the `assert_unchecked`, the above function produces the following with optimizations
+/// enabled:
+///
+/// ```asm
+/// next_value:
+///         test    rdi, rdi
+///         je      .LBB0_1
+///         mov     eax, dword ptr [rdi]
+///         inc     eax
+///         ret
+/// .LBB0_1:
+///         mov     eax, -1
+///         ret
+/// ```
+///
+/// Adding the assertion allows the optimizer to remove the extra check:
+///
+/// ```asm
+/// next_value:
+///         mov     eax, dword ptr [rdi]
+///         inc     eax
+///         ret
+/// ```
+///
+/// This example is quite unlike anything that would be used in the real world: it is redundant
+/// to put an assertion right next to code that checks the same thing, and dereferencing a
+/// pointer already has the builtin assumption that it is nonnull. However, it illustrates the
+/// kind of changes the optimizer can make even when the behavior is less obviously related.
+#[track_caller]
 #[inline(always)]
 #[doc(alias = "assume")]
-#[track_caller]
-#[unstable(feature = "hint_assert_unchecked", issue = "119131")]
-#[rustc_const_unstable(feature = "const_hint_assert_unchecked", issue = "119131")]
+#[stable(feature = "hint_assert_unchecked", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "hint_assert_unchecked", since = "CURRENT_RUSTC_VERSION")]
 pub const unsafe fn assert_unchecked(cond: bool) {
     // SAFETY: The caller promised `cond` is true.
     unsafe {
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 9ba1c6a4154..720da0feece 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -959,7 +959,7 @@ extern "rust-intrinsic" {
 /// not be used if the invariant can be discovered by the optimizer on its
 /// own, or if it does not enable any significant optimizations.
 ///
-/// This intrinsic does not have a stable counterpart.
+/// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`].
 #[rustc_const_stable(feature = "const_assume", since = "1.77.0")]
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index b892e111588..30734c020b3 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -460,7 +460,7 @@ extern "rust-intrinsic" {
     /// `T` must be an integer vector.
     ///
     /// `U` must be either the smallest unsigned integer with at least as many bits as the length
-    /// of `T`, or the smallest array of `u8` with as many bits as the length of `T`.
+    /// of `T`, or the smallest array of `u8` with at least as many bits as the length of `T`.
     ///
     /// Each element is truncated to a single bit and packed into the result.
     ///
@@ -472,12 +472,19 @@ extern "rust-intrinsic" {
     /// * On little endian, the least significant bit corresponds to the first vector element.
     /// * On big endian, the least significant bit corresponds to the last vector element.
     ///
-    /// For example, `[!0, 0, !0, !0]` packs to `0b1101` on little endian and `0b1011` on big
-    /// endian.
+    /// For example, `[!0, 0, !0, !0]` packs to
+    /// - `0b1101u8` or `[0b1101]` on little endian, and
+    /// - `0b1011u8` or `[0b1011]` on big endian.
     ///
-    /// To consider a larger example, `[!0, 0, 0, 0, 0, 0, 0, 0, !0, !0, 0, 0, 0, 0, !0, 0]` packs
-    /// to `[0b00000001, 0b01000011]` or `0b0100001100000001` on little endian, and `[0b10000000,
-    /// 0b11000010]` or `0b1000000011000010` on big endian.
+    /// To consider a larger example,
+    /// `[!0, 0, 0, 0, 0, 0, 0, 0, !0, !0, 0, 0, 0, 0, !0, 0]` packs to
+    /// - `0b0100001100000001u16` or `[0b00000001, 0b01000011]` on little endian, and
+    /// - `0b1000000011000010u16` or `[0b10000000, 0b11000010]` on big endian.
+    ///
+    /// And finally, a non-power-of-2 example with multiple bytes:
+    /// `[!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]` packs to
+    /// - `0b0101001011u16` or `[0b01001011, 0b01]` on little endian, and
+    /// - `0b1101001010u16` or `[0b11, 0b01001010]` on big endian.
     ///
     /// # Safety
     /// `x` must contain only `0` and `!0`.
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 05a5f268905..1bde4488cc9 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -159,7 +159,7 @@ pub(crate) struct GenericShunt<'a, I, R> {
     residual: &'a mut Option<R>,
 }
 
-/// Process the given iterator as if it yielded a the item's `Try::Output`
+/// Process the given iterator as if it yielded the item's `Try::Output`
 /// type instead. Any `Try::Residual`s encountered will stop the inner iterator
 /// and be propagated back to the overall result.
 pub(crate) fn try_process<I, T, R, F, U>(iter: I, mut f: F) -> ChangeOutputType<I::Item, U>
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 61a45789013..86660f2e375 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -1,3 +1,5 @@
+use super::TrustedLen;
+
 /// Conversion from an [`Iterator`].
 ///
 /// By implementing `FromIterator` for a type, you define how it will be
@@ -460,6 +462,27 @@ pub trait Extend<A> {
     fn extend_reserve(&mut self, additional: usize) {
         let _ = additional;
     }
+
+    /// Extends a collection with one element, without checking there is enough capacity for it.
+    ///
+    /// # Safety
+    ///
+    /// **For callers:** This must only be called when we know the collection has enough capacity
+    /// to contain the new item, for example because we previously called `extend_reserve`.
+    ///
+    /// **For implementors:** For a collection to unsafely rely on this method's safety precondition (that is,
+    /// invoke UB if they are violated), it must implement `extend_reserve` correctly. In other words,
+    /// callers may assume that if they `extend_reserve`ed enough space they can call this method.
+
+    // This method is for internal usage only. It is only on the trait because of specialization's limitations.
+    #[unstable(feature = "extend_one_unchecked", issue = "none")]
+    #[doc(hidden)]
+    unsafe fn extend_one_unchecked(&mut self, item: A)
+    where
+        Self: Sized,
+    {
+        self.extend_one(item);
+    }
 }
 
 #[stable(feature = "extend_for_unit", since = "1.28.0")]
@@ -499,33 +522,102 @@ where
     fn extend<T: IntoIterator<Item = (A, B)>>(&mut self, into_iter: T) {
         let (a, b) = self;
         let iter = into_iter.into_iter();
+        SpecTupleExtend::extend(iter, a, b);
+    }
+
+    fn extend_one(&mut self, item: (A, B)) {
+        self.0.extend_one(item.0);
+        self.1.extend_one(item.1);
+    }
+
+    fn extend_reserve(&mut self, additional: usize) {
+        self.0.extend_reserve(additional);
+        self.1.extend_reserve(additional);
+    }
+
+    unsafe fn extend_one_unchecked(&mut self, item: (A, B)) {
+        // SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`.
+        unsafe {
+            self.0.extend_one_unchecked(item.0);
+            self.1.extend_one_unchecked(item.1);
+        }
+    }
+}
+
+fn default_extend_tuple<A, B, ExtendA, ExtendB>(
+    iter: impl Iterator<Item = (A, B)>,
+    a: &mut ExtendA,
+    b: &mut ExtendB,
+) where
+    ExtendA: Extend<A>,
+    ExtendB: Extend<B>,
+{
+    fn extend<'a, A, B>(
+        a: &'a mut impl Extend<A>,
+        b: &'a mut impl Extend<B>,
+    ) -> impl FnMut((), (A, B)) + 'a {
+        move |(), (t, u)| {
+            a.extend_one(t);
+            b.extend_one(u);
+        }
+    }
+
+    let (lower_bound, _) = iter.size_hint();
+    if lower_bound > 0 {
+        a.extend_reserve(lower_bound);
+        b.extend_reserve(lower_bound);
+    }
+
+    iter.fold((), extend(a, b));
+}
+
+trait SpecTupleExtend<A, B> {
+    fn extend(self, a: &mut A, b: &mut B);
+}
 
+impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter
+where
+    ExtendA: Extend<A>,
+    ExtendB: Extend<B>,
+    Iter: Iterator<Item = (A, B)>,
+{
+    default fn extend(self, a: &mut ExtendA, b: &mut ExtendB) {
+        default_extend_tuple(self, a, b);
+    }
+}
+
+impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter
+where
+    ExtendA: Extend<A>,
+    ExtendB: Extend<B>,
+    Iter: TrustedLen<Item = (A, B)>,
+{
+    fn extend(self, a: &mut ExtendA, b: &mut ExtendB) {
         fn extend<'a, A, B>(
             a: &'a mut impl Extend<A>,
             b: &'a mut impl Extend<B>,
         ) -> impl FnMut((), (A, B)) + 'a {
-            move |(), (t, u)| {
-                a.extend_one(t);
-                b.extend_one(u);
+            // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
+            // so its `size_hint` is exact.
+            move |(), (t, u)| unsafe {
+                a.extend_one_unchecked(t);
+                b.extend_one_unchecked(u);
             }
         }
 
-        let (lower_bound, _) = iter.size_hint();
+        let (lower_bound, upper_bound) = self.size_hint();
+
+        if upper_bound.is_none() {
+            // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
+            default_extend_tuple(self, a, b);
+            return;
+        }
+
         if lower_bound > 0 {
             a.extend_reserve(lower_bound);
             b.extend_reserve(lower_bound);
         }
 
-        iter.fold((), extend(a, b));
-    }
-
-    fn extend_one(&mut self, item: (A, B)) {
-        self.0.extend_one(item.0);
-        self.1.extend_one(item.1);
-    }
-
-    fn extend_reserve(&mut self, additional: usize) {
-        self.0.extend_reserve(additional);
-        self.1.extend_reserve(additional);
+        self.fold((), extend(a, b));
     }
 }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 128f1c81827..0f82f01e57a 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -127,7 +127,6 @@
 #![feature(const_fmt_arguments_new)]
 #![feature(const_hash)]
 #![feature(const_heap)]
-#![feature(const_hint_assert_unchecked)]
 #![feature(const_index_range_slice_index)]
 #![feature(const_int_from_str)]
 #![feature(const_intrinsic_copy)]
@@ -396,6 +395,8 @@ pub mod panicking;
 #[unstable(feature = "core_pattern_types", issue = "none")]
 pub mod pat;
 pub mod pin;
+#[unstable(feature = "new_range_api", issue = "125687")]
+pub mod range;
 pub mod result;
 pub mod sync;
 
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 9054ade2d79..dd4b6e82343 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1266,6 +1266,20 @@ impl<T> SizedTypeProperties for T {}
 /// // ^^^ error[E0616]: field `private` of struct `Struct` is private
 /// ```
 ///
+/// Only [`Sized`] fields are supported, but the container may be unsized:
+/// ```
+/// # use core::mem;
+/// #[repr(C)]
+/// pub struct Struct {
+///     a: u8,
+///     b: [u8],
+/// }
+///
+/// assert_eq!(mem::offset_of!(Struct, a), 0); // OK
+/// // assert_eq!(mem::offset_of!(Struct, b), 1);
+/// // ^^^ error[E0277]: doesn't have a size known at compile-time
+/// ```
+///
 /// Note that type layout is, in general, [subject to change and
 /// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). If
 /// layout stability is required, consider using an [explicit `repr` attribute].
diff --git a/library/core/src/num/dec2flt/lemire.rs b/library/core/src/num/dec2flt/lemire.rs
index 3bc052df7a6..01642e1b111 100644
--- a/library/core/src/num/dec2flt/lemire.rs
+++ b/library/core/src/num/dec2flt/lemire.rs
@@ -157,7 +157,7 @@ fn compute_product_approx(q: i64, w: u64, precision: usize) -> (u64, u64) {
         // Need to do a second multiplication to get better precision
         // for the lower product. This will always be exact
         // where q is < 55, since 5^55 < 2^128. If this wraps,
-        // then we need to need to round up the hi product.
+        // then we need to round up the hi product.
         let (_, second_hi) = full_multiplication(w, hi5);
         first_lo = first_lo.wrapping_add(second_hi);
         if second_hi > first_lo {
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 3c58b0af9c2..e74300d6c2f 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -507,8 +507,8 @@ impl f16 {
     ///
     /// ```
     /// #![feature(f16)]
-    /// # // FIXME(f16_f128): remove when `extendhfsf2` and `truncsfhf2` are available
-    /// # #[cfg(target_os = "linux")] {
+    /// # // FIXME(f16_f128): extendhfsf2, truncsfhf2, __gnu_h2f_ieee, __gnu_f2h_ieee missing for many platforms
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
     ///
     /// let x = 2.0_f16;
     /// let abs_difference = (x.recip() - (1.0 / x)).abs();
@@ -528,8 +528,8 @@ impl f16 {
     ///
     /// ```
     /// #![feature(f16)]
-    /// # // FIXME(f16_f128): remove when `extendhfsf2` and `truncsfhf2` are available
-    /// # #[cfg(target_os = "linux")] {
+    /// # // FIXME(f16_f128): extendhfsf2, truncsfhf2, __gnu_h2f_ieee, __gnu_f2h_ieee missing for many platforms
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
     ///
     /// let angle = std::f16::consts::PI;
     ///
@@ -551,8 +551,8 @@ impl f16 {
     ///
     /// ```
     /// #![feature(f16)]
-    /// # // FIXME(f16_f128): remove when `extendhfsf2` and `truncsfhf2` are available
-    /// # #[cfg(target_os = "linux")] {
+    /// # // FIXME(f16_f128): extendhfsf2, truncsfhf2, __gnu_h2f_ieee, __gnu_f2h_ieee missing for many platforms
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
     ///
     /// let angle = 180.0f16;
     ///
@@ -870,6 +870,8 @@ impl f16 {
     ///
     /// ```
     /// #![feature(f16)]
+    /// # // FIXME(f16_f128): extendhfsf2, truncsfhf2, __gnu_h2f_ieee, __gnu_f2h_ieee missing for many platforms
+    /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
     ///
     /// struct GoodBoy {
     ///     name: &'static str,
@@ -897,6 +899,7 @@ impl f16 {
     ///         .zip([-5.0, 0.1, 10.0, 99.0, f16::INFINITY, f16::NAN].iter())
     ///         .for_each(|(a, b)| assert_eq!(a.to_bits(), b.to_bits()))
     /// }
+    /// # }
     /// ```
     #[inline]
     #[must_use]
diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs
index 56ede02673c..37c338dd9b7 100644
--- a/library/core/src/panic.rs
+++ b/library/core/src/panic.rs
@@ -12,7 +12,7 @@ use crate::any::Any;
 pub use self::location::Location;
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub use self::panic_info::PanicInfo;
-#[unstable(feature = "panic_info_message", issue = "66745")]
+#[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
 pub use self::panic_info::PanicMessage;
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index 91953fd656b..6bbb9c30171 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -24,7 +24,7 @@ pub struct PanicInfo<'a> {
 /// that were given to the `panic!()` macro.
 ///
 /// See [`PanicInfo::message`].
-#[unstable(feature = "panic_info_message", issue = "66745")]
+#[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
 pub struct PanicMessage<'a> {
     message: fmt::Arguments<'a>,
 }
@@ -57,7 +57,7 @@ impl<'a> PanicInfo<'a> {
     /// }
     /// ```
     #[must_use]
-    #[unstable(feature = "panic_info_message", issue = "66745")]
+    #[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
     pub fn message(&self) -> PanicMessage<'_> {
         PanicMessage { message: self.message }
     }
@@ -164,7 +164,7 @@ impl<'a> PanicMessage<'a> {
     /// For most cases with placeholders, this function will return `None`.
     ///
     /// See [`fmt::Arguments::as_str`] for details.
-    #[unstable(feature = "panic_info_message", issue = "66745")]
+    #[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
     #[must_use]
     #[inline]
@@ -173,7 +173,7 @@ impl<'a> PanicMessage<'a> {
     }
 }
 
-#[unstable(feature = "panic_info_message", issue = "66745")]
+#[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
 impl Display for PanicMessage<'_> {
     #[inline]
     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -181,7 +181,7 @@ impl Display for PanicMessage<'_> {
     }
 }
 
-#[unstable(feature = "panic_info_message", issue = "66745")]
+#[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
 impl fmt::Debug for PanicMessage<'_> {
     #[inline]
     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 5537d26669a..68cf8203433 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -390,37 +390,26 @@ impl<T: ?Sized> *const T {
         if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
     }
 
-    /// Calculates the offset from a pointer.
+    /// Adds an offset to a pointer.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
-    ///   pointer must be either in bounds or at the end of the same [allocated object].
-    ///   (If it is zero, then the function is always well-defined.)
+    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
     ///
-    /// * The computed offset, **in bytes**, cannot overflow an `isize`.
+    /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
+    ///   [allocated object], and the entire memory range between `self` and the result must be in
+    ///   bounds of that allocated object. In particular, this range must not "wrap around" the edge
+    ///   of the address space.
     ///
-    /// * The offset being in bounds cannot rely on "wrapping around" the address
-    ///   space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
-    ///
-    /// The compiler and standard library generally tries to ensure allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec`
-    /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
-    /// `vec.as_ptr().add(vec.len())` is always safe.
-    ///
-    /// Most platforms fundamentally can't even construct such an allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
+    /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
+    /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
+    /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
+    /// safe.
     ///
     /// Consider using [`wrapping_offset`] instead if these constraints are
     /// difficult to satisfy. The only advantage of this method is that it
@@ -611,8 +600,7 @@ impl<T: ?Sized> *const T {
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
     /// * `self` and `origin` must either
     ///
@@ -623,26 +611,10 @@ impl<T: ?Sized> *const T {
     /// * The distance between the pointers, in bytes, must be an exact multiple
     ///   of the size of `T`.
     ///
-    /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
-    ///
-    /// * The distance being in bounds cannot rely on "wrapping around" the address space.
-    ///
-    /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
-    /// address space, so two pointers within some value of any Rust type `T` will always satisfy
-    /// the last two conditions. The standard library also generally ensures that allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
-    /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
-    /// always satisfies the last two conditions.
-    ///
-    /// Most platforms fundamentally can't even construct such a large allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
-    /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
-    /// such large allocations either.)
+    /// As a consequence, the absolute distance between the pointers, in bytes, computed on
+    /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
+    /// implied by the in-bounds requirement, and the fact that no allocated object can be larger
+    /// than `isize::MAX` bytes.
     ///
     /// The requirement for pointers to be derived from the same allocated object is primarily
     /// needed for `const`-compatibility: the distance between pointers into *different* allocated
@@ -879,37 +851,26 @@ impl<T: ?Sized> *const T {
         }
     }
 
-    /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
+    /// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
-    ///   pointer must be either in bounds or at the end of the same [allocated object].
-    ///   (If it is zero, then the function is always well-defined.)
+    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
     ///
-    /// * The computed offset, **in bytes**, cannot overflow an `isize`.
+    /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
+    ///   [allocated object], and the entire memory range between `self` and the result must be in
+    ///   bounds of that allocated object. In particular, this range must not "wrap around" the edge
+    ///   of the address space.
     ///
-    /// * The offset being in bounds cannot rely on "wrapping around" the address
-    ///   space. That is, the infinite-precision sum must fit in a `usize`.
-    ///
-    /// The compiler and standard library generally tries to ensure allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec`
-    /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
-    /// `vec.as_ptr().add(vec.len())` is always safe.
-    ///
-    /// Most platforms fundamentally can't even construct such an allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
+    /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
+    /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
+    /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
+    /// safe.
     ///
     /// Consider using [`wrapping_add`] instead if these constraints are
     /// difficult to satisfy. The only advantage of this method is that it
@@ -963,7 +924,7 @@ impl<T: ?Sized> *const T {
         unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer (convenience for
+    /// Subtracts an offset from a pointer (convenience for
     /// `.offset((count as isize).wrapping_neg())`).
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
@@ -971,30 +932,19 @@ impl<T: ?Sized> *const T {
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
-    ///
-    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
-    ///   pointer must be either in bounds or at the end of the same [allocated object].
-    ///   (If it is zero, then the function is always well-defined.)
-    ///
-    /// * The computed offset cannot exceed `isize::MAX` **bytes**.
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The offset being in bounds cannot rely on "wrapping around" the address
-    ///   space. That is, the infinite-precision sum must fit in a usize.
+    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
     ///
-    /// The compiler and standard library generally tries to ensure allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec`
-    /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
-    /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
+    /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
+    ///   [allocated object], and the entire memory range between `self` and the result must be in
+    ///   bounds of that allocated object. In particular, this range must not "wrap around" the edge
+    ///   of the address space.
     ///
-    /// Most platforms fundamentally can't even construct such an allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
+    /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
+    /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
+    /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
+    /// safe.
     ///
     /// Consider using [`wrapping_sub`] instead if these constraints are
     /// difficult to satisfy. The only advantage of this method is that it
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 30d5b2cfc5a..0dc910db5b9 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -404,37 +404,26 @@ impl<T: ?Sized> *mut T {
         if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
     }
 
-    /// Calculates the offset from a pointer.
+    /// Adds an offset to a pointer.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
-    ///   pointer must be either in bounds or at the end of the same [allocated object].
-    ///   (If it is zero, then the function is always well-defined.)
+    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
     ///
-    /// * The computed offset, **in bytes**, cannot overflow an `isize`.
+    /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
+    ///   [allocated object], and the entire memory range between `self` and the result must be in
+    ///   bounds of that allocated object. In particular, this range must not "wrap around" the edge
+    ///   of the address space.
     ///
-    /// * The offset being in bounds cannot rely on "wrapping around" the address
-    ///   space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
-    ///
-    /// The compiler and standard library generally tries to ensure allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec`
-    /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
-    /// `vec.as_ptr().add(vec.len())` is always safe.
-    ///
-    /// Most platforms fundamentally can't even construct such an allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
+    /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
+    /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
+    /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
+    /// safe.
     ///
     /// Consider using [`wrapping_offset`] instead if these constraints are
     /// difficult to satisfy. The only advantage of this method is that it
@@ -836,8 +825,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
     /// * `self` and `origin` must either
     ///
@@ -848,26 +836,10 @@ impl<T: ?Sized> *mut T {
     /// * The distance between the pointers, in bytes, must be an exact multiple
     ///   of the size of `T`.
     ///
-    /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
-    ///
-    /// * The distance being in bounds cannot rely on "wrapping around" the address space.
-    ///
-    /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
-    /// address space, so two pointers within some value of any Rust type `T` will always satisfy
-    /// the last two conditions. The standard library also generally ensures that allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
-    /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
-    /// always satisfies the last two conditions.
-    ///
-    /// Most platforms fundamentally can't even construct such a large allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
-    /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
-    /// such large allocations either.)
+    /// As a consequence, the absolute distance between the pointers, in bytes, computed on
+    /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
+    /// implied by the in-bounds requirement, and the fact that no allocated object can be larger
+    /// than `isize::MAX` bytes.
     ///
     /// The requirement for pointers to be derived from the same allocated object is primarily
     /// needed for `const`-compatibility: the distance between pointers into *different* allocated
@@ -1020,37 +992,26 @@ impl<T: ?Sized> *mut T {
         unsafe { (self as *const T).sub_ptr(origin) }
     }
 
-    /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
+    /// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
-    ///   pointer must be either in bounds or at the end of the same [allocated object].
-    ///   (If it is zero, then the function is always well-defined.)
+    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
     ///
-    /// * The computed offset, **in bytes**, cannot overflow an `isize`.
+    /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
+    ///   [allocated object], and the entire memory range between `self` and the result must be in
+    ///   bounds of that allocated object. In particular, this range must not "wrap around" the edge
+    ///   of the address space.
     ///
-    /// * The offset being in bounds cannot rely on "wrapping around" the address
-    ///   space. That is, the infinite-precision sum must fit in a `usize`.
-    ///
-    /// The compiler and standard library generally tries to ensure allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec`
-    /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
-    /// `vec.as_ptr().add(vec.len())` is always safe.
-    ///
-    /// Most platforms fundamentally can't even construct such an allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
+    /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
+    /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
+    /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
+    /// safe.
     ///
     /// Consider using [`wrapping_add`] instead if these constraints are
     /// difficult to satisfy. The only advantage of this method is that it
@@ -1104,7 +1065,7 @@ impl<T: ?Sized> *mut T {
         unsafe { self.cast::<u8>().add(count).with_metadata_of(self) }
     }
 
-    /// Calculates the offset from a pointer (convenience for
+    /// Subtracts an offset from a pointer (convenience for
     /// `.offset((count as isize).wrapping_neg())`).
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
@@ -1112,30 +1073,19 @@ impl<T: ?Sized> *mut T {
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
-    ///
-    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
-    ///   pointer must be either in bounds or at the end of the same [allocated object].
-    ///   (If it is zero, then the function is always well-defined.)
-    ///
-    /// * The computed offset cannot exceed `isize::MAX` **bytes**.
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The offset being in bounds cannot rely on "wrapping around" the address
-    ///   space. That is, the infinite-precision sum must fit in a usize.
+    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
     ///
-    /// The compiler and standard library generally tries to ensure allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec`
-    /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
-    /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
+    /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
+    ///   [allocated object], and the entire memory range between `self` and the result must be in
+    ///   bounds of that allocated object. In particular, this range must not "wrap around" the edge
+    ///   of the address space.
     ///
-    /// Most platforms fundamentally can't even construct such an allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
+    /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
+    /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
+    /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
+    /// safe.
     ///
     /// Consider using [`wrapping_sub`] instead if these constraints are
     /// difficult to satisfy. The only advantage of this method is that it
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 0504a0fc32f..75a99e14fda 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -476,36 +476,26 @@ impl<T: ?Sized> NonNull<T> {
         unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
     }
 
-    /// Calculates the offset from a pointer.
+    /// Adds an offset to a pointer.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * Both the starting and resulting pointer must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
     ///
-    /// * The computed offset, **in bytes**, cannot overflow an `isize`.
+    /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
+    ///   [allocated object], and the entire memory range between `self` and the result must be in
+    ///   bounds of that allocated object. In particular, this range must not "wrap around" the edge
+    ///   of the address space.
     ///
-    /// * The offset being in bounds cannot rely on "wrapping around" the address
-    ///   space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
-    ///
-    /// The compiler and standard library generally tries to ensure allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec`
-    /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
-    /// `vec.as_ptr().add(vec.len())` is always safe.
-    ///
-    /// Most platforms fundamentally can't even construct such an allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
+    /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
+    /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
+    /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
+    /// safe.
     ///
     /// [allocated object]: crate::ptr#allocated-object
     ///
@@ -562,36 +552,26 @@ impl<T: ?Sized> NonNull<T> {
         unsafe { NonNull { pointer: self.pointer.byte_offset(count) } }
     }
 
-    /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
+    /// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
     /// offset of `3 * size_of::<T>()` bytes.
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
-    ///
-    /// * Both the starting and resulting pointer must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The computed offset, **in bytes**, cannot overflow an `isize`.
+    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
     ///
-    /// * The offset being in bounds cannot rely on "wrapping around" the address
-    ///   space. That is, the infinite-precision sum must fit in a `usize`.
+    /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
+    ///   [allocated object], and the entire memory range between `self` and the result must be in
+    ///   bounds of that allocated object. In particular, this range must not "wrap around" the edge
+    ///   of the address space.
     ///
-    /// The compiler and standard library generally tries to ensure allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec`
-    /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
-    /// `vec.as_ptr().add(vec.len())` is always safe.
-    ///
-    /// Most platforms fundamentally can't even construct such an allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
+    /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
+    /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
+    /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
+    /// safe.
     ///
     /// [allocated object]: crate::ptr#allocated-object
     ///
@@ -649,7 +629,7 @@ impl<T: ?Sized> NonNull<T> {
         unsafe { NonNull { pointer: self.pointer.byte_add(count) } }
     }
 
-    /// Calculates the offset from a pointer (convenience for
+    /// Subtracts an offset from a pointer (convenience for
     /// `.offset((count as isize).wrapping_neg())`).
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
@@ -657,29 +637,19 @@ impl<T: ?Sized> NonNull<T> {
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
-    ///
-    /// * Both the starting and resulting pointer must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
-    ///
-    /// * The computed offset cannot exceed `isize::MAX` **bytes**.
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * The offset being in bounds cannot rely on "wrapping around" the address
-    ///   space. That is, the infinite-precision sum must fit in a usize.
+    /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`.
     ///
-    /// The compiler and standard library generally tries to ensure allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec`
-    /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
-    /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
+    /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
+    ///   [allocated object], and the entire memory range between `self` and the result must be in
+    ///   bounds of that allocated object. In particular, this range must not "wrap around" the edge
+    ///   of the address space.
     ///
-    /// Most platforms fundamentally can't even construct such an allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
+    /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset
+    /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement.
+    /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always
+    /// safe.
     ///
     /// [allocated object]: crate::ptr#allocated-object
     ///
@@ -761,38 +731,21 @@ impl<T: ?Sized> NonNull<T> {
     ///
     /// # Safety
     ///
-    /// If any of the following conditions are violated, the result is Undefined
-    /// Behavior:
+    /// If any of the following conditions are violated, the result is Undefined Behavior:
     ///
-    /// * Both `self` and `origin` must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * `self` and `origin` must either
     ///
-    /// * Both pointers must be *derived from* a pointer to the same object.
-    ///   (See below for an example.)
+    ///   * both be *derived from* a pointer to the same [allocated object], and the memory range between
+    ///     the two pointers must be either empty or in bounds of that object. (See below for an example.)
+    ///   * or both be derived from an integer literal/constant, and point to the same address.
     ///
     /// * The distance between the pointers, in bytes, must be an exact multiple
     ///   of the size of `T`.
     ///
-    /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`.
-    ///
-    /// * The distance being in bounds cannot rely on "wrapping around" the address space.
-    ///
-    /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the
-    /// address space, so two pointers within some value of any Rust type `T` will always satisfy
-    /// the last two conditions. The standard library also generally ensures that allocations
-    /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they
-    /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())`
-    /// always satisfies the last two conditions.
-    ///
-    /// Most platforms fundamentally can't even construct such a large allocation.
-    /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
-    /// However, some 32-bit and 16-bit platforms may successfully serve a request for
-    /// more than `isize::MAX` bytes with things like Physical Address
-    /// Extension. As such, memory acquired directly from allocators or memory
-    /// mapped files *may* be too large to handle with this function.
-    /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on
-    /// such large allocations either.)
+    /// As a consequence, the absolute distance between the pointers, in bytes, computed on
+    /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is
+    /// implied by the in-bounds requirement, and the fact that no allocated object can be larger
+    /// than `isize::MAX` bytes.
     ///
     /// The requirement for pointers to be derived from the same allocated object is primarily
     /// needed for `const`-compatibility: the distance between pointers into *different* allocated
diff --git a/library/core/src/range.rs b/library/core/src/range.rs
new file mode 100644
index 00000000000..bfbbf123b1c
--- /dev/null
+++ b/library/core/src/range.rs
@@ -0,0 +1,494 @@
+//! # Experimental replacement range types
+//!
+//! The types within this module are meant to replace the existing
+//! `Range`, `RangeInclusive`, and `RangeFrom` types in a future edition.
+//!
+//! ```
+//! #![feature(new_range_api)]
+//! use core::range::{Range, RangeFrom, RangeInclusive};
+//!
+//! let arr = [0, 1, 2, 3, 4];
+//! assert_eq!(arr[                      ..   ], [0, 1, 2, 3, 4]);
+//! assert_eq!(arr[                      .. 3 ], [0, 1, 2      ]);
+//! assert_eq!(arr[                      ..=3 ], [0, 1, 2, 3   ]);
+//! assert_eq!(arr[     RangeFrom::from(1..  )], [   1, 2, 3, 4]);
+//! assert_eq!(arr[         Range::from(1..3 )], [   1, 2      ]);
+//! assert_eq!(arr[RangeInclusive::from(1..=3)], [   1, 2, 3   ]);
+//! ```
+
+use crate::fmt;
+use crate::hash::Hash;
+
+mod iter;
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+pub mod legacy;
+
+#[doc(inline)]
+pub use crate::ops::{Bound, OneSidedRange, RangeBounds, RangeFull, RangeTo, RangeToInclusive};
+
+use Bound::{Excluded, Included, Unbounded};
+
+#[doc(inline)]
+pub use crate::iter::Step;
+
+#[doc(inline)]
+pub use iter::{IterRange, IterRangeFrom, IterRangeInclusive};
+
+/// A (half-open) range bounded inclusively below and exclusively above
+/// (`start..end` in a future edition).
+///
+/// The range `start..end` contains all values with `start <= x < end`.
+/// It is empty if `start >= end`.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(new_range_api)]
+/// use core::range::Range;
+///
+/// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 });
+/// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum());
+/// ```
+#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
+#[unstable(feature = "new_range_api", issue = "125687")]
+pub struct Range<Idx> {
+    /// The lower bound of the range (inclusive).
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    pub start: Idx,
+    /// The upper bound of the range (exclusive).
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    pub end: Idx,
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.start.fmt(fmt)?;
+        write!(fmt, "..")?;
+        self.end.fmt(fmt)?;
+        Ok(())
+    }
+}
+
+impl<Idx: Step> Range<Idx> {
+    /// Create an iterator over the elements within this range.
+    ///
+    /// Shorthand for `.clone().into_iter()`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::Range;
+    ///
+    /// let mut i = Range::from(3..9).iter().map(|n| n*n);
+    /// assert_eq!(i.next(), Some(9));
+    /// assert_eq!(i.next(), Some(16));
+    /// assert_eq!(i.next(), Some(25));
+    /// ```
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    #[inline]
+    pub fn iter(&self) -> IterRange<Idx> {
+        self.clone().into_iter()
+    }
+}
+
+impl<Idx: PartialOrd<Idx>> Range<Idx> {
+    /// Returns `true` if `item` is contained in the range.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::Range;
+    ///
+    /// assert!(!Range::from(3..5).contains(&2));
+    /// assert!( Range::from(3..5).contains(&3));
+    /// assert!( Range::from(3..5).contains(&4));
+    /// assert!(!Range::from(3..5).contains(&5));
+    ///
+    /// assert!(!Range::from(3..3).contains(&3));
+    /// assert!(!Range::from(3..2).contains(&3));
+    ///
+    /// assert!( Range::from(0.0..1.0).contains(&0.5));
+    /// assert!(!Range::from(0.0..1.0).contains(&f32::NAN));
+    /// assert!(!Range::from(0.0..f32::NAN).contains(&0.5));
+    /// assert!(!Range::from(f32::NAN..1.0).contains(&0.5));
+    /// ```
+    #[inline]
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    pub fn contains<U>(&self, item: &U) -> bool
+    where
+        Idx: PartialOrd<U>,
+        U: ?Sized + PartialOrd<Idx>,
+    {
+        <Self as RangeBounds<Idx>>::contains(self, item)
+    }
+
+    /// Returns `true` if the range contains no items.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::Range;
+    ///
+    /// assert!(!Range::from(3..5).is_empty());
+    /// assert!( Range::from(3..3).is_empty());
+    /// assert!( Range::from(3..2).is_empty());
+    /// ```
+    ///
+    /// The range is empty if either side is incomparable:
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::Range;
+    ///
+    /// assert!(!Range::from(3.0..5.0).is_empty());
+    /// assert!( Range::from(3.0..f32::NAN).is_empty());
+    /// assert!( Range::from(f32::NAN..5.0).is_empty());
+    /// ```
+    #[inline]
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    pub fn is_empty(&self) -> bool {
+        !(self.start < self.end)
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> RangeBounds<T> for Range<T> {
+    fn start_bound(&self) -> Bound<&T> {
+        Included(&self.start)
+    }
+    fn end_bound(&self) -> Bound<&T> {
+        Excluded(&self.end)
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> RangeBounds<T> for Range<&T> {
+    fn start_bound(&self) -> Bound<&T> {
+        Included(self.start)
+    }
+    fn end_bound(&self) -> Bound<&T> {
+        Excluded(self.end)
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> From<Range<T>> for legacy::Range<T> {
+    #[inline]
+    fn from(value: Range<T>) -> Self {
+        Self { start: value.start, end: value.end }
+    }
+}
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> From<legacy::Range<T>> for Range<T> {
+    #[inline]
+    fn from(value: legacy::Range<T>) -> Self {
+        Self { start: value.start, end: value.end }
+    }
+}
+
+/// A range bounded inclusively below and above (`start..=end`).
+///
+/// The `RangeInclusive` `start..=end` contains all values with `x >= start`
+/// and `x <= end`. It is empty unless `start <= end`.
+///
+/// # Examples
+///
+/// The `start..=end` syntax is a `RangeInclusive`:
+///
+/// ```
+/// #![feature(new_range_api)]
+/// use core::range::RangeInclusive;
+///
+/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, end: 5 });
+/// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum());
+/// ```
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[unstable(feature = "new_range_api", issue = "125687")]
+pub struct RangeInclusive<Idx> {
+    /// The lower bound of the range (inclusive).
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    pub start: Idx,
+    /// The upper bound of the range (inclusive).
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    pub end: Idx,
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.start.fmt(fmt)?;
+        write!(fmt, "..=")?;
+        self.end.fmt(fmt)?;
+        Ok(())
+    }
+}
+
+impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
+    /// Returns `true` if `item` is contained in the range.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::RangeInclusive;
+    ///
+    /// assert!(!RangeInclusive::from(3..=5).contains(&2));
+    /// assert!( RangeInclusive::from(3..=5).contains(&3));
+    /// assert!( RangeInclusive::from(3..=5).contains(&4));
+    /// assert!( RangeInclusive::from(3..=5).contains(&5));
+    /// assert!(!RangeInclusive::from(3..=5).contains(&6));
+    ///
+    /// assert!( RangeInclusive::from(3..=3).contains(&3));
+    /// assert!(!RangeInclusive::from(3..=2).contains(&3));
+    ///
+    /// assert!( RangeInclusive::from(0.0..=1.0).contains(&1.0));
+    /// assert!(!RangeInclusive::from(0.0..=1.0).contains(&f32::NAN));
+    /// assert!(!RangeInclusive::from(0.0..=f32::NAN).contains(&0.0));
+    /// assert!(!RangeInclusive::from(f32::NAN..=1.0).contains(&1.0));
+    /// ```
+    #[inline]
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    pub fn contains<U>(&self, item: &U) -> bool
+    where
+        Idx: PartialOrd<U>,
+        U: ?Sized + PartialOrd<Idx>,
+    {
+        <Self as RangeBounds<Idx>>::contains(self, item)
+    }
+
+    /// Returns `true` if the range contains no items.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::RangeInclusive;
+    ///
+    /// assert!(!RangeInclusive::from(3..=5).is_empty());
+    /// assert!(!RangeInclusive::from(3..=3).is_empty());
+    /// assert!( RangeInclusive::from(3..=2).is_empty());
+    /// ```
+    ///
+    /// The range is empty if either side is incomparable:
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::RangeInclusive;
+    ///
+    /// assert!(!RangeInclusive::from(3.0..=5.0).is_empty());
+    /// assert!( RangeInclusive::from(3.0..=f32::NAN).is_empty());
+    /// assert!( RangeInclusive::from(f32::NAN..=5.0).is_empty());
+    /// ```
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        !(self.start <= self.end)
+    }
+}
+
+impl<Idx: Step> RangeInclusive<Idx> {
+    /// Create an iterator over the elements within this range.
+    ///
+    /// Shorthand for `.clone().into_iter()`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::RangeInclusive;
+    ///
+    /// let mut i = RangeInclusive::from(3..=8).iter().map(|n| n*n);
+    /// assert_eq!(i.next(), Some(9));
+    /// assert_eq!(i.next(), Some(16));
+    /// assert_eq!(i.next(), Some(25));
+    /// ```
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    #[inline]
+    pub fn iter(&self) -> IterRangeInclusive<Idx> {
+        self.clone().into_iter()
+    }
+}
+
+impl RangeInclusive<usize> {
+    /// Converts to an exclusive `Range` for `SliceIndex` implementations.
+    /// The caller is responsible for dealing with `end == usize::MAX`.
+    #[inline]
+    pub(crate) const fn into_slice_range(self) -> Range<usize> {
+        Range { start: self.start, end: self.end + 1 }
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> RangeBounds<T> for RangeInclusive<T> {
+    fn start_bound(&self) -> Bound<&T> {
+        Included(&self.start)
+    }
+    fn end_bound(&self) -> Bound<&T> {
+        Included(&self.end)
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> RangeBounds<T> for RangeInclusive<&T> {
+    fn start_bound(&self) -> Bound<&T> {
+        Included(self.start)
+    }
+    fn end_bound(&self) -> Bound<&T> {
+        Included(self.end)
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
+    #[inline]
+    fn from(value: RangeInclusive<T>) -> Self {
+        Self::new(value.start, value.end)
+    }
+}
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> From<legacy::RangeInclusive<T>> for RangeInclusive<T> {
+    #[inline]
+    fn from(value: legacy::RangeInclusive<T>) -> Self {
+        assert!(
+            !value.exhausted,
+            "attempted to convert from an exhausted `legacy::RangeInclusive` (unspecified behavior)"
+        );
+
+        let (start, end) = value.into_inner();
+        RangeInclusive { start, end }
+    }
+}
+
+/// A range only bounded inclusively below (`start..`).
+///
+/// The `RangeFrom` `start..` contains all values with `x >= start`.
+///
+/// *Note*: Overflow in the [`Iterator`] implementation (when the contained
+/// data type reaches its numerical limit) is allowed to panic, wrap, or
+/// saturate. This behavior is defined by the implementation of the [`Step`]
+/// trait. For primitive integers, this follows the normal rules, and respects
+/// the overflow checks profile (panic in debug, wrap in release). Note also
+/// that overflow happens earlier than you might assume: the overflow happens
+/// in the call to `next` that yields the maximum value, as the range must be
+/// set to a state to yield the next value.
+///
+/// [`Step`]: crate::iter::Step
+///
+/// # Examples
+///
+/// The `start..` syntax is a `RangeFrom`:
+///
+/// ```
+/// #![feature(new_range_api)]
+/// use core::range::RangeFrom;
+///
+/// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 });
+/// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum());
+/// ```
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[unstable(feature = "new_range_api", issue = "125687")]
+pub struct RangeFrom<Idx> {
+    /// The lower bound of the range (inclusive).
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    pub start: Idx,
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.start.fmt(fmt)?;
+        write!(fmt, "..")?;
+        Ok(())
+    }
+}
+
+impl<Idx: Step> RangeFrom<Idx> {
+    /// Create an iterator over the elements within this range.
+    ///
+    /// Shorthand for `.clone().into_iter()`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::RangeFrom;
+    ///
+    /// let mut i = RangeFrom::from(3..).iter().map(|n| n*n);
+    /// assert_eq!(i.next(), Some(9));
+    /// assert_eq!(i.next(), Some(16));
+    /// assert_eq!(i.next(), Some(25));
+    /// ```
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    #[inline]
+    pub fn iter(&self) -> IterRangeFrom<Idx> {
+        self.clone().into_iter()
+    }
+}
+
+impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
+    /// Returns `true` if `item` is contained in the range.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(new_range_api)]
+    /// use core::range::RangeFrom;
+    ///
+    /// assert!(!RangeFrom::from(3..).contains(&2));
+    /// assert!( RangeFrom::from(3..).contains(&3));
+    /// assert!( RangeFrom::from(3..).contains(&1_000_000_000));
+    ///
+    /// assert!( RangeFrom::from(0.0..).contains(&0.5));
+    /// assert!(!RangeFrom::from(0.0..).contains(&f32::NAN));
+    /// assert!(!RangeFrom::from(f32::NAN..).contains(&0.5));
+    /// ```
+    #[inline]
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    pub fn contains<U>(&self, item: &U) -> bool
+    where
+        Idx: PartialOrd<U>,
+        U: ?Sized + PartialOrd<Idx>,
+    {
+        <Self as RangeBounds<Idx>>::contains(self, item)
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> RangeBounds<T> for RangeFrom<T> {
+    fn start_bound(&self) -> Bound<&T> {
+        Included(&self.start)
+    }
+    fn end_bound(&self) -> Bound<&T> {
+        Unbounded
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> RangeBounds<T> for RangeFrom<&T> {
+    fn start_bound(&self) -> Bound<&T> {
+        Included(self.start)
+    }
+    fn end_bound(&self) -> Bound<&T> {
+        Unbounded
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> From<RangeFrom<T>> for legacy::RangeFrom<T> {
+    #[inline]
+    fn from(value: RangeFrom<T>) -> Self {
+        Self { start: value.start }
+    }
+}
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<T> From<legacy::RangeFrom<T>> for RangeFrom<T> {
+    #[inline]
+    fn from(value: legacy::RangeFrom<T>) -> Self {
+        Self { start: value.start }
+    }
+}
diff --git a/library/core/src/range/iter.rs b/library/core/src/range/iter.rs
new file mode 100644
index 00000000000..2b7db475ffb
--- /dev/null
+++ b/library/core/src/range/iter.rs
@@ -0,0 +1,340 @@
+use crate::num::NonZero;
+use crate::range::{legacy, Range, RangeFrom, RangeInclusive};
+
+use crate::iter::{
+    FusedIterator, Step, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, TrustedStep,
+};
+
+/// By-value [`Range`] iterator.
+#[unstable(feature = "new_range_api", issue = "125687")]
+#[derive(Debug, Clone)]
+pub struct IterRange<A>(legacy::Range<A>);
+
+impl<A> IterRange<A> {
+    /// Returns the remainder of the range being iterated over.
+    pub fn remainder(self) -> Range<A> {
+        Range { start: self.0.start, end: self.0.end }
+    }
+}
+
+/// Safety: This macro must only be used on types that are `Copy` and result in ranges
+/// which have an exact `size_hint()` where the upper bound must not be `None`.
+macro_rules! unsafe_range_trusted_random_access_impl {
+    ($($t:ty)*) => ($(
+        #[doc(hidden)]
+        #[unstable(feature = "trusted_random_access", issue = "none")]
+        unsafe impl TrustedRandomAccess for IterRange<$t> {}
+
+        #[doc(hidden)]
+        #[unstable(feature = "trusted_random_access", issue = "none")]
+        unsafe impl TrustedRandomAccessNoCoerce for IterRange<$t> {
+            const MAY_HAVE_SIDE_EFFECT: bool = false;
+        }
+    )*)
+}
+
+unsafe_range_trusted_random_access_impl! {
+    usize u8 u16
+    isize i8 i16
+}
+
+#[cfg(target_pointer_width = "32")]
+unsafe_range_trusted_random_access_impl! {
+    u32 i32
+}
+
+#[cfg(target_pointer_width = "64")]
+unsafe_range_trusted_random_access_impl! {
+    u32 i32
+    u64 i64
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<A: Step> Iterator for IterRange<A> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        self.0.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.0.size_hint()
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.0.count()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<A> {
+        self.0.nth(n)
+    }
+
+    #[inline]
+    fn last(self) -> Option<A> {
+        self.0.last()
+    }
+
+    #[inline]
+    fn min(self) -> Option<A>
+    where
+        A: Ord,
+    {
+        self.0.min()
+    }
+
+    #[inline]
+    fn max(self) -> Option<A>
+    where
+        A: Ord,
+    {
+        self.0.max()
+    }
+
+    #[inline]
+    fn is_sorted(self) -> bool {
+        true
+    }
+
+    #[inline]
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.0.advance_by(n)
+    }
+
+    #[inline]
+    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
+    where
+        Self: TrustedRandomAccessNoCoerce,
+    {
+        // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index
+        // that is in bounds.
+        // Additionally Self: TrustedRandomAccess is only implemented for Copy types
+        // which means even repeated reads of the same index would be safe.
+        unsafe { Step::forward_unchecked(self.0.start.clone(), idx) }
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<A: Step> DoubleEndedIterator for IterRange<A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        self.0.next_back()
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<A> {
+        self.0.nth_back(n)
+    }
+
+    #[inline]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.0.advance_back_by(n)
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: TrustedStep> TrustedLen for IterRange<A> {}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<A: Step> FusedIterator for IterRange<A> {}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<A: Step> IntoIterator for Range<A> {
+    type Item = A;
+    type IntoIter = IterRange<A>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        IterRange(self.into())
+    }
+}
+
+/// By-value [`RangeInclusive`] iterator.
+#[unstable(feature = "new_range_api", issue = "125687")]
+#[derive(Debug, Clone)]
+pub struct IterRangeInclusive<A>(legacy::RangeInclusive<A>);
+
+impl<A: Step> IterRangeInclusive<A> {
+    /// Returns the remainder of the range being iterated over.
+    ///
+    /// If the iterator is exhausted or empty, returns `None`.
+    pub fn remainder(self) -> Option<RangeInclusive<A>> {
+        if self.0.is_empty() {
+            return None;
+        }
+
+        Some(RangeInclusive { start: self.0.start, end: self.0.end })
+    }
+}
+
+#[unstable(feature = "trusted_random_access", issue = "none")]
+impl<A: Step> Iterator for IterRangeInclusive<A> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        self.0.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.0.size_hint()
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.0.count()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<A> {
+        self.0.nth(n)
+    }
+
+    #[inline]
+    fn last(self) -> Option<A> {
+        self.0.last()
+    }
+
+    #[inline]
+    fn min(self) -> Option<A>
+    where
+        A: Ord,
+    {
+        self.0.min()
+    }
+
+    #[inline]
+    fn max(self) -> Option<A>
+    where
+        A: Ord,
+    {
+        self.0.max()
+    }
+
+    #[inline]
+    fn is_sorted(self) -> bool {
+        true
+    }
+
+    #[inline]
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.0.advance_by(n)
+    }
+}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<A: Step> DoubleEndedIterator for IterRangeInclusive<A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        self.0.next_back()
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<A> {
+        self.0.nth_back(n)
+    }
+
+    #[inline]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.0.advance_back_by(n)
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: TrustedStep> TrustedLen for IterRangeInclusive<A> {}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<A: Step> FusedIterator for IterRangeInclusive<A> {}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<A: Step> IntoIterator for RangeInclusive<A> {
+    type Item = A;
+    type IntoIter = IterRangeInclusive<A>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        IterRangeInclusive(self.into())
+    }
+}
+
+// These macros generate `ExactSizeIterator` impls for various range types.
+//
+// * `ExactSizeIterator::len` is required to always return an exact `usize`,
+//   so no range can be longer than `usize::MAX`.
+// * For integer types in `Range<_>` this is the case for types narrower than or as wide as `usize`.
+//   For integer types in `RangeInclusive<_>`
+//   this is the case for types *strictly narrower* than `usize`
+//   since e.g. `(0..=u64::MAX).len()` would be `u64::MAX + 1`.
+macro_rules! range_exact_iter_impl {
+    ($($t:ty)*) => ($(
+        #[unstable(feature = "new_range_api", issue = "125687")]
+        impl ExactSizeIterator for IterRange<$t> { }
+    )*)
+}
+
+macro_rules! range_incl_exact_iter_impl {
+    ($($t:ty)*) => ($(
+        #[unstable(feature = "new_range_api", issue = "125687")]
+        impl ExactSizeIterator for IterRangeInclusive<$t> { }
+    )*)
+}
+
+range_exact_iter_impl! {
+    usize u8 u16
+    isize i8 i16
+}
+
+range_incl_exact_iter_impl! {
+    u8
+    i8
+}
+
+/// By-value [`RangeFrom`] iterator.
+#[unstable(feature = "new_range_api", issue = "125687")]
+#[derive(Debug, Clone)]
+pub struct IterRangeFrom<A>(legacy::RangeFrom<A>);
+
+impl<A> IterRangeFrom<A> {
+    /// Returns the remainder of the range being iterated over.
+    pub fn remainder(self) -> RangeFrom<A> {
+        RangeFrom { start: self.0.start }
+    }
+}
+
+#[unstable(feature = "trusted_random_access", issue = "none")]
+impl<A: Step> Iterator for IterRangeFrom<A> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        self.0.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.0.size_hint()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<A> {
+        self.0.nth(n)
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: TrustedStep> TrustedLen for IterRangeFrom<A> {}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<A: Step> FusedIterator for IterRangeFrom<A> {}
+
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl<A: Step> IntoIterator for RangeFrom<A> {
+    type Item = A;
+    type IntoIter = IterRangeFrom<A>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        IterRangeFrom(self.into())
+    }
+}
diff --git a/library/core/src/range/legacy.rs b/library/core/src/range/legacy.rs
new file mode 100644
index 00000000000..6723c4903f7
--- /dev/null
+++ b/library/core/src/range/legacy.rs
@@ -0,0 +1,10 @@
+//! # Legacy range types
+//!
+//! The types within this module will be replaced by the types
+//! [`Range`], [`RangeInclusive`], and [`RangeFrom`] in the parent
+//! module, [`core::range`].
+//!
+//! The types here are equivalent to those in [`core::ops`].
+
+#[doc(inline)]
+pub use crate::ops::{Range, RangeFrom, RangeInclusive};
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 143dbd8a496..2624a44bb4b 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -2,6 +2,7 @@
 
 use crate::intrinsics::const_eval_select;
 use crate::ops;
+use crate::range;
 use crate::ub_checks::assert_unsafe_precondition;
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -147,7 +148,8 @@ const unsafe fn get_offset_len_mut_noubcheck<T>(
 }
 
 mod private_slice_index {
-    use super::ops;
+    use super::{ops, range};
+
     #[stable(feature = "slice_get_slice", since = "1.28.0")]
     pub trait Sealed {}
 
@@ -168,6 +170,13 @@ mod private_slice_index {
     #[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")]
     impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {}
 
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    impl Sealed for range::Range<usize> {}
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    impl Sealed for range::RangeInclusive<usize> {}
+    #[unstable(feature = "new_range_api", issue = "125687")]
+    impl Sealed for range::RangeFrom<usize> {}
+
     impl Sealed for ops::IndexRange {}
 }
 
@@ -473,6 +482,43 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
     }
 }
 
+#[unstable(feature = "new_range_api", issue = "125687")]
+unsafe impl<T> SliceIndex<[T]> for range::Range<usize> {
+    type Output = [T];
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&[T]> {
+        ops::Range::from(self).get(slice)
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+        ops::Range::from(self).get_mut(slice)
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { ops::Range::from(self).get_unchecked(slice) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { ops::Range::from(self).get_unchecked_mut(slice) }
+    }
+
+    #[inline(always)]
+    fn index(self, slice: &[T]) -> &[T] {
+        ops::Range::from(self).index(slice)
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+        ops::Range::from(self).index_mut(slice)
+    }
+}
+
 /// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
@@ -559,6 +605,43 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
     }
 }
 
+#[unstable(feature = "new_range_api", issue = "125687")]
+unsafe impl<T> SliceIndex<[T]> for range::RangeFrom<usize> {
+    type Output = [T];
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&[T]> {
+        ops::RangeFrom::from(self).get(slice)
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+        ops::RangeFrom::from(self).get_mut(slice)
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { ops::RangeFrom::from(self).get_unchecked(slice) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { ops::RangeFrom::from(self).get_unchecked_mut(slice) }
+    }
+
+    #[inline]
+    fn index(self, slice: &[T]) -> &[T] {
+        ops::RangeFrom::from(self).index(slice)
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+        ops::RangeFrom::from(self).index_mut(slice)
+    }
+}
+
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
 unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
@@ -643,6 +726,43 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
     }
 }
 
+#[unstable(feature = "new_range_api", issue = "125687")]
+unsafe impl<T> SliceIndex<[T]> for range::RangeInclusive<usize> {
+    type Output = [T];
+
+    #[inline]
+    fn get(self, slice: &[T]) -> Option<&[T]> {
+        ops::RangeInclusive::from(self).get(slice)
+    }
+
+    #[inline]
+    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+        ops::RangeInclusive::from(self).get_mut(slice)
+    }
+
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { ops::RangeInclusive::from(self).get_unchecked(slice) }
+    }
+
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { ops::RangeInclusive::from(self).get_unchecked_mut(slice) }
+    }
+
+    #[inline]
+    fn index(self, slice: &[T]) -> &[T] {
+        ops::RangeInclusive::from(self).index(slice)
+    }
+
+    #[inline]
+    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+        ops::RangeInclusive::from(self).index_mut(slice)
+    }
+}
+
 /// The methods `index` and `index_mut` panic if the end of the range is out of bounds.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
 #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
@@ -780,7 +900,7 @@ where
 
 /// Performs bounds-checking of a range without panicking.
 ///
-/// This is a version of [`range`] that returns [`None`] instead of panicking.
+/// This is a version of [`range()`] that returns [`None`] instead of panicking.
 ///
 /// # Examples
 ///
diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs
index 4008639095b..2d9c4ac9fcf 100644
--- a/library/core/src/slice/sort/stable/drift.rs
+++ b/library/core/src/slice/sort/stable/drift.rs
@@ -200,7 +200,7 @@ fn logical_merge<T, F: FnMut(&T, &T) -> bool>(
     // If one or both of the runs are sorted do a physical merge, using
     // quicksort to sort the unsorted run if present. We also *need* to
     // physically merge if the combined runs would not fit in the scratch space
-    // anymore (as this would mean we are no longer able to to quicksort them).
+    // anymore (as this would mean we are no longer able to quicksort them).
     let len = v.len();
     let can_fit_in_scratch = len <= scratch.len();
     if !can_fit_in_scratch || left.sorted() || right.sorted() {
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index ba2d6f64496..3de5546c4d4 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -4,6 +4,7 @@ use crate::cmp::Ordering;
 use crate::intrinsics::unchecked_sub;
 use crate::ops;
 use crate::ptr;
+use crate::range;
 use crate::slice::SliceIndex;
 use crate::ub_checks::assert_unsafe_precondition;
 
@@ -261,6 +262,108 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
     }
 }
 
+#[unstable(feature = "new_range_api", issue = "125687")]
+unsafe impl SliceIndex<str> for range::Range<usize> {
+    type Output = str;
+    #[inline]
+    fn get(self, slice: &str) -> Option<&Self::Output> {
+        if self.start <= self.end
+            && slice.is_char_boundary(self.start)
+            && slice.is_char_boundary(self.end)
+        {
+            // SAFETY: just checked that `start` and `end` are on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            // We also checked char boundaries, so this is valid UTF-8.
+            Some(unsafe { &*self.get_unchecked(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+        if self.start <= self.end
+            && slice.is_char_boundary(self.start)
+            && slice.is_char_boundary(self.end)
+        {
+            // SAFETY: just checked that `start` and `end` are on a char boundary.
+            // We know the pointer is unique because we got it from `slice`.
+            Some(unsafe { &mut *self.get_unchecked_mut(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+        let slice = slice as *const [u8];
+
+        assert_unsafe_precondition!(
+            // We'd like to check that the bounds are on char boundaries,
+            // but there's not really a way to do so without reading
+            // behind the pointer, which has aliasing implications.
+            // It's also not possible to move this check up to
+            // `str::get_unchecked` without adding a special function
+            // to `SliceIndex` just for this.
+            check_library_ub,
+            "str::get_unchecked requires that the range is within the string slice",
+            (
+                start: usize = self.start,
+                end: usize = self.end,
+                len: usize = slice.len()
+            ) => end >= start && end <= len,
+        );
+
+        // SAFETY: the caller guarantees that `self` is in bounds of `slice`
+        // which satisfies all the conditions for `add`.
+        unsafe {
+            let new_len = unchecked_sub(self.end, self.start);
+            ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) as *const str
+        }
+    }
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+        let slice = slice as *mut [u8];
+
+        assert_unsafe_precondition!(
+            check_library_ub,
+            "str::get_unchecked_mut requires that the range is within the string slice",
+            (
+                start: usize = self.start,
+                end: usize = self.end,
+                len: usize = slice.len()
+            ) => end >= start && end <= len,
+        );
+
+        // SAFETY: see comments for `get_unchecked`.
+        unsafe {
+            let new_len = unchecked_sub(self.end, self.start);
+            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) as *mut str
+        }
+    }
+    #[inline]
+    fn index(self, slice: &str) -> &Self::Output {
+        let (start, end) = (self.start, self.end);
+        match self.get(slice) {
+            Some(s) => s,
+            None => super::slice_error_fail(slice, start, end),
+        }
+    }
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+        // is_char_boundary checks that the index is in [0, .len()]
+        // cannot reuse `get` as above, because of NLL trouble
+        if self.start <= self.end
+            && slice.is_char_boundary(self.start)
+            && slice.is_char_boundary(self.end)
+        {
+            // SAFETY: just checked that `start` and `end` are on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            unsafe { &mut *self.get_unchecked_mut(slice) }
+        } else {
+            super::slice_error_fail(slice, self.start, self.end)
+        }
+    }
+}
+
 /// Implements substring slicing for arbitrary bounds.
 ///
 /// Returns a slice of the given string bounded by the byte indices
@@ -453,6 +556,61 @@ unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
     }
 }
 
+#[unstable(feature = "new_range_api", issue = "125687")]
+unsafe impl SliceIndex<str> for range::RangeFrom<usize> {
+    type Output = str;
+    #[inline]
+    fn get(self, slice: &str) -> Option<&Self::Output> {
+        if slice.is_char_boundary(self.start) {
+            // SAFETY: just checked that `start` is on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            Some(unsafe { &*self.get_unchecked(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+        if slice.is_char_boundary(self.start) {
+            // SAFETY: just checked that `start` is on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            Some(unsafe { &mut *self.get_unchecked_mut(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+        let len = (slice as *const [u8]).len();
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { (self.start..len).get_unchecked(slice) }
+    }
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+        let len = (slice as *mut [u8]).len();
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { (self.start..len).get_unchecked_mut(slice) }
+    }
+    #[inline]
+    fn index(self, slice: &str) -> &Self::Output {
+        let (start, end) = (self.start, slice.len());
+        match self.get(slice) {
+            Some(s) => s,
+            None => super::slice_error_fail(slice, start, end),
+        }
+    }
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+        if slice.is_char_boundary(self.start) {
+            // SAFETY: just checked that `start` is on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            unsafe { &mut *self.get_unchecked_mut(slice) }
+        } else {
+            super::slice_error_fail(slice, self.start, slice.len())
+        }
+    }
+}
+
 /// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut
 /// self[begin ..= end]`.
 ///
@@ -507,6 +665,43 @@ unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
     }
 }
 
+#[unstable(feature = "new_range_api", issue = "125687")]
+unsafe impl SliceIndex<str> for range::RangeInclusive<usize> {
+    type Output = str;
+    #[inline]
+    fn get(self, slice: &str) -> Option<&Self::Output> {
+        if self.end == usize::MAX { None } else { self.into_slice_range().get(slice) }
+    }
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+        if self.end == usize::MAX { None } else { self.into_slice_range().get_mut(slice) }
+    }
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
+        unsafe { self.into_slice_range().get_unchecked(slice) }
+    }
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
+        unsafe { self.into_slice_range().get_unchecked_mut(slice) }
+    }
+    #[inline]
+    fn index(self, slice: &str) -> &Self::Output {
+        if self.end == usize::MAX {
+            str_index_overflow_fail();
+        }
+        self.into_slice_range().index(slice)
+    }
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+        if self.end == usize::MAX {
+            str_index_overflow_fail();
+        }
+        self.into_slice_range().index_mut(slice)
+    }
+}
+
 /// Implements substring slicing with syntax `&self[..= end]` or `&mut
 /// self[..= end]`.
 ///
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index df108f5e0e4..efc07f38f68 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -1069,7 +1069,6 @@ impl AtomicBool {
     /// # Examples
     ///
     /// ```
-    /// #![feature(atomic_bool_fetch_not)]
     /// use std::sync::atomic::{AtomicBool, Ordering};
     ///
     /// let foo = AtomicBool::new(true);
@@ -1081,7 +1080,7 @@ impl AtomicBool {
     /// assert_eq!(foo.load(Ordering::SeqCst), true);
     /// ```
     #[inline]
-    #[unstable(feature = "atomic_bool_fetch_not", issue = "98485")]
+    #[stable(feature = "atomic_bool_fetch_not", since = "CURRENT_RUSTC_VERSION")]
     #[cfg(target_has_atomic = "8")]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn fetch_not(&self, order: Ordering) -> bool {
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 73c556249be..d66f558078e 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -620,13 +620,14 @@ impl Duration {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(duration_abs_diff)]
     /// use std::time::Duration;
     ///
     /// assert_eq!(Duration::new(100, 0).abs_diff(Duration::new(80, 0)), Duration::new(20, 0));
     /// assert_eq!(Duration::new(100, 400_000_000).abs_diff(Duration::new(110, 0)), Duration::new(9, 600_000_000));
     /// ```
-    #[unstable(feature = "duration_abs_diff", issue = "117618")]
+    #[stable(feature = "duration_abs_diff", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "duration_abs_diff", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_allow_const_fn_unstable(const_option)]
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
     #[inline]
diff --git a/library/core/tests/fmt/builders.rs b/library/core/tests/fmt/builders.rs
index 487ce46be28..2bdc334b7c0 100644
--- a/library/core/tests/fmt/builders.rs
+++ b/library/core/tests/fmt/builders.rs
@@ -441,7 +441,7 @@ mod debug_map {
             }
         }
 
-        format!("{Foo:?}");
+        let _ = format!("{Foo:?}");
     }
 
     #[test]
@@ -455,7 +455,7 @@ mod debug_map {
             }
         }
 
-        format!("{Foo:?}");
+        let _ = format!("{Foo:?}");
     }
 
     #[test]
@@ -469,7 +469,7 @@ mod debug_map {
             }
         }
 
-        format!("{Foo:?}");
+        let _ = format!("{Foo:?}");
     }
 }
 
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 57127df51eb..83a615fcd8b 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -30,7 +30,6 @@
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
 #![feature(dec2flt)]
-#![feature(duration_abs_diff)]
 #![feature(duration_consts_float)]
 #![feature(duration_constants)]
 #![feature(duration_constructors)]
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index 4dc36120608..77abb9125f6 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -36,18 +36,14 @@ use core::panic::PanicPayload;
 cfg_if::cfg_if! {
     if #[cfg(target_os = "emscripten")] {
         #[path = "emcc.rs"]
-        mod real_imp;
+        mod imp;
     } else if #[cfg(target_os = "hermit")] {
         #[path = "hermit.rs"]
-        mod real_imp;
+        mod imp;
     } else if #[cfg(target_os = "l4re")] {
         // L4Re is unix family but does not yet support unwinding.
         #[path = "dummy.rs"]
-        mod real_imp;
-    } else if #[cfg(all(target_env = "msvc", not(target_arch = "arm")))] {
-        // LLVM does not support unwinding on 32 bit ARM msvc (thumbv7a-pc-windows-msvc)
-        #[path = "seh.rs"]
-        mod real_imp;
+        mod imp;
     } else if #[cfg(any(
         all(target_family = "windows", target_env = "gnu"),
         target_os = "psp",
@@ -58,7 +54,16 @@ cfg_if::cfg_if! {
         target_family = "wasm",
     ))] {
         #[path = "gcc.rs"]
-        mod real_imp;
+        mod imp;
+    } else if #[cfg(miri)] {
+        // Use the Miri runtime on Windows as miri doesn't support funclet based unwinding,
+        // only landingpad based unwinding. Also use the Miri runtime on unsupported platforms.
+        #[path = "miri.rs"]
+        mod imp;
+    } else if #[cfg(all(target_env = "msvc", not(target_arch = "arm")))] {
+        // LLVM does not support unwinding on 32 bit ARM msvc (thumbv7a-pc-windows-msvc)
+        #[path = "seh.rs"]
+        mod imp;
     } else {
         // Targets that don't support unwinding.
         // - os=none ("bare metal" targets)
@@ -67,20 +72,7 @@ cfg_if::cfg_if! {
         // - nvptx64-nvidia-cuda
         // - arch=avr
         #[path = "dummy.rs"]
-        mod real_imp;
-    }
-}
-
-cfg_if::cfg_if! {
-    if #[cfg(miri)] {
-        // Use the Miri runtime.
-        // We still need to also load the normal runtime above, as rustc expects certain lang
-        // items from there to be defined.
-        #[path = "miri.rs"]
         mod imp;
-    } else {
-        // Use the real runtime.
-        use real_imp as imp;
     }
 }
 
diff --git a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
index 8a1079042f0..3b6388d0f27 100644
--- a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
+++ b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
@@ -30,6 +30,8 @@ where
         use core::arch::arm::{uint8x8_t, vtbl1_u8};
         #[cfg(target_arch = "wasm32")]
         use core::arch::wasm32 as wasm;
+        #[cfg(target_arch = "wasm64")]
+        use core::arch::wasm64 as wasm;
         #[cfg(target_arch = "x86")]
         use core::arch::x86;
         #[cfg(target_arch = "x86_64")]
diff --git a/library/std/build.rs b/library/std/build.rs
index 55388648a14..c542ba81eed 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -99,7 +99,9 @@ fn main() {
         // the compiler-builtins update. <https://github.com/rust-lang/rust/issues/123885>
         ("x86" | "x86_64", _) => false,
         // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee`
-        ("powerpc" | "powerpc64" | "powerpc64le", _) => false,
+        ("powerpc" | "powerpc64", _) => false,
+        // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee`
+        ("mips" | "mips32r6" | "mips64" | "mips64r6", _) => false,
         // Missing `__extendhfsf` and `__truncsfhf`
         ("riscv32" | "riscv64", _) => false,
         // Most OSs are missing `__extendhfsf` and `__truncsfhf`
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index c9d3934ad70..a5cefe2292b 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -28,7 +28,7 @@
 //!
 //! # Layout
 //! Tagged values are 64 bits, with the 2 least significant bits used for the
-//! tag. This means there are there are 4 "variants":
+//! tag. This means there are 4 "variants":
 //!
 //! - **Tag 0b00**: The first variant is equivalent to
 //!   `ErrorData::SimpleMessage`, and holds a `&'static SimpleMessage` directly.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 27ed2e4137c..66aeb35acee 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -266,6 +266,7 @@
 )]
 #![cfg_attr(any(windows, target_os = "uefi"), feature(round_char_boundary))]
 #![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))]
+#![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))]
 #![cfg_attr(
     all(any(target_arch = "x86_64", target_arch = "x86"), target_os = "uefi"),
     feature(stdarch_x86_has_cpuid)
@@ -334,12 +335,10 @@
 #![feature(fmt_internals)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
-#![feature(hint_assert_unchecked)]
 #![feature(ip)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(panic_can_unwind)]
-#![feature(panic_info_message)]
 #![feature(panic_internals)]
 #![feature(pointer_is_aligned_to)]
 #![feature(portable_simd)]
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 8c7fc4cb2e4..a1f83029d27 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -175,6 +175,11 @@ impl Drop for OwnedFd {
             // the file descriptor was closed or not, and if we retried (for
             // something like EINTR), we might close another valid file descriptor
             // opened after we closed ours.
+            // However, this is usually justified, as some of the major Unices
+            // do make sure to always close the FD, even when `close()` is interrupted,
+            // and the scenario is rare to begin with.
+            // Helpful link to an epic discussion by POSIX workgroup:
+            // http://austingroupbugs.net/view.php?id=529
             #[cfg(not(target_os = "hermit"))]
             {
                 #[cfg(unix)]
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index caae8f924d2..d5121a554bf 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1519,6 +1519,74 @@ impl PathBuf {
         true
     }
 
+    /// Append [`self.extension`] with `extension`.
+    ///
+    /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
+    /// returns `true` and updates the extension otherwise.
+    ///
+    /// # Caveats
+    ///
+    /// The appended `extension` may contain dots and will be used in its entirety,
+    /// but only the part after the final dot will be reflected in
+    /// [`self.extension`].
+    ///
+    /// See the examples below.
+    ///
+    /// [`self.file_name`]: Path::file_name
+    /// [`self.extension`]: Path::extension
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(path_add_extension)]
+    ///
+    /// use std::path::{Path, PathBuf};
+    ///
+    /// let mut p = PathBuf::from("/feel/the");
+    ///
+    /// p.add_extension("formatted");
+    /// assert_eq!(Path::new("/feel/the.formatted"), p.as_path());
+    ///
+    /// p.add_extension("dark.side");
+    /// assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path());
+    ///
+    /// p.set_extension("cookie");
+    /// assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
+    ///
+    /// p.add_extension("");
+    /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
+    /// ```
+    #[unstable(feature = "path_add_extension", issue = "127292")]
+    pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
+        self._add_extension(extension.as_ref())
+    }
+
+    fn _add_extension(&mut self, extension: &OsStr) -> bool {
+        let file_name = match self.file_name() {
+            None => return false,
+            Some(f) => f.as_encoded_bytes(),
+        };
+
+        let new = extension;
+        if !new.is_empty() {
+            // truncate until right after the file name
+            // this is necessary for trimming the trailing slash
+            let end_file_name = file_name[file_name.len()..].as_ptr().addr();
+            let start = self.inner.as_encoded_bytes().as_ptr().addr();
+            self.inner.truncate(end_file_name.wrapping_sub(start));
+
+            // append the new extension
+            self.inner.reserve_exact(new.len() + 1);
+            self.inner.push(OsStr::new("."));
+            self.inner.push(new);
+        }
+
+        true
+    }
+
     /// Yields a mutable reference to the underlying [`OsString`] instance.
     ///
     /// # Examples
@@ -2656,6 +2724,32 @@ impl Path {
         new_path
     }
 
+    /// Creates an owned [`PathBuf`] like `self` but with the extension added.
+    ///
+    /// See [`PathBuf::add_extension`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(path_add_extension)]
+    ///
+    /// use std::path::{Path, PathBuf};
+    ///
+    /// let path = Path::new("foo.rs");
+    /// assert_eq!(path.with_added_extension("txt"), PathBuf::from("foo.rs.txt"));
+    ///
+    /// let path = Path::new("foo.tar.gz");
+    /// assert_eq!(path.with_added_extension(""), PathBuf::from("foo.tar.gz"));
+    /// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz"));
+    /// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt"));
+    /// ```
+    #[unstable(feature = "path_add_extension", issue = "127292")]
+    pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
+        let mut new_path = self.to_path_buf();
+        new_path.add_extension(extension);
+        new_path
+    }
+
     /// Produces an iterator over the [`Component`]s of the path.
     ///
     /// When parsing the path, there is a small amount of normalization:
@@ -3098,15 +3192,19 @@ impl Hash for Path {
         let bytes = &bytes[prefix_len..];
 
         let mut component_start = 0;
-        let mut bytes_hashed = 0;
+        // track some extra state to avoid prefix collisions.
+        // ["foo", "bar"] and ["foobar"], will have the same payload bytes
+        // but result in different chunk_bits
+        let mut chunk_bits: usize = 0;
 
         for i in 0..bytes.len() {
             let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) };
             if is_sep {
                 if i > component_start {
                     let to_hash = &bytes[component_start..i];
+                    chunk_bits = chunk_bits.wrapping_add(to_hash.len());
+                    chunk_bits = chunk_bits.rotate_right(2);
                     h.write(to_hash);
-                    bytes_hashed += to_hash.len();
                 }
 
                 // skip over separator and optionally a following CurDir item
@@ -3127,11 +3225,12 @@ impl Hash for Path {
 
         if component_start < bytes.len() {
             let to_hash = &bytes[component_start..];
+            chunk_bits = chunk_bits.wrapping_add(to_hash.len());
+            chunk_bits = chunk_bits.rotate_right(2);
             h.write(to_hash);
-            bytes_hashed += to_hash.len();
         }
 
-        h.write_usize(bytes_hashed);
+        h.write_usize(chunk_bits);
     }
 }
 
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index 92702b395df..3ade4fb892f 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -1402,6 +1402,37 @@ pub fn test_set_extension() {
 }
 
 #[test]
+pub fn test_add_extension() {
+    macro_rules! tfe (
+        ($path:expr, $ext:expr, $expected:expr, $output:expr) => ({
+            let mut p = PathBuf::from($path);
+            let output = p.add_extension($ext);
+            assert!(p.to_str() == Some($expected) && output == $output,
+                    "adding extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
+                    $path, $ext, $expected, $output,
+                    p.to_str().unwrap(), output);
+        });
+    );
+
+    tfe!("foo", "txt", "foo.txt", true);
+    tfe!("foo.bar", "txt", "foo.bar.txt", true);
+    tfe!("foo.bar.baz", "txt", "foo.bar.baz.txt", true);
+    tfe!(".test", "txt", ".test.txt", true);
+    tfe!("foo.txt", "", "foo.txt", true);
+    tfe!("foo", "", "foo", true);
+    tfe!("", "foo", "", false);
+    tfe!(".", "foo", ".", false);
+    tfe!("foo/", "bar", "foo.bar", true);
+    tfe!("foo/.", "bar", "foo.bar", true);
+    tfe!("..", "foo", "..", false);
+    tfe!("foo/..", "bar", "foo/..", false);
+    tfe!("/", "foo", "/", false);
+
+    // edge cases
+    tfe!("/foo.ext////", "bar", "/foo.ext.bar", true);
+}
+
+#[test]
 pub fn test_with_extension() {
     macro_rules! twe (
         ($input:expr, $extension:expr, $expected:expr) => ({
@@ -1442,6 +1473,49 @@ pub fn test_with_extension() {
 }
 
 #[test]
+pub fn test_with_added_extension() {
+    macro_rules! twe (
+        ($input:expr, $extension:expr, $expected:expr) => ({
+            let input = Path::new($input);
+            let output = input.with_added_extension($extension);
+
+            assert!(
+                output.to_str() == Some($expected),
+                "calling Path::new({:?}).with_added_extension({:?}): Expected {:?}, got {:?}",
+                $input, $extension, $expected, output,
+            );
+        });
+    );
+
+    twe!("foo", "txt", "foo.txt");
+    twe!("foo.bar", "txt", "foo.bar.txt");
+    twe!("foo.bar.baz", "txt", "foo.bar.baz.txt");
+    twe!(".test", "txt", ".test.txt");
+    twe!("foo.txt", "", "foo.txt");
+    twe!("foo", "", "foo");
+    twe!("", "foo", "");
+    twe!(".", "foo", ".");
+    twe!("foo/", "bar", "foo.bar");
+    twe!("foo/.", "bar", "foo.bar");
+    twe!("..", "foo", "..");
+    twe!("foo/..", "bar", "foo/..");
+    twe!("/", "foo", "/");
+
+    // edge cases
+    twe!("/foo.ext////", "bar", "/foo.ext.bar");
+
+    // New extension is smaller than file name
+    twe!("aaa_aaa_aaa", "bbb_bbb", "aaa_aaa_aaa.bbb_bbb");
+    // New extension is greater than file name
+    twe!("bbb_bbb", "aaa_aaa_aaa", "bbb_bbb.aaa_aaa_aaa");
+
+    // New extension is smaller than previous extension
+    twe!("ccc.aaa_aaa_aaa", "bbb_bbb", "ccc.aaa_aaa_aaa.bbb_bbb");
+    // New extension is greater than previous extension
+    twe!("ccc.bbb_bbb", "aaa_aaa_aaa", "ccc.bbb_bbb.aaa_aaa_aaa");
+}
+
+#[test]
 fn test_eq_receivers() {
     use crate::borrow::Cow;
 
@@ -1545,6 +1619,20 @@ pub fn test_compare() {
     relative_from: Some("")
     );
 
+    tc!("foo//", "foo",
+    eq: true,
+    starts_with: true,
+    ends_with: true,
+    relative_from: Some("")
+    );
+
+    tc!("foo///", "foo",
+    eq: true,
+    starts_with: true,
+    ends_with: true,
+    relative_from: Some("")
+    );
+
     tc!("foo/.", "foo",
     eq: true,
     starts_with: true,
@@ -1559,6 +1647,20 @@ pub fn test_compare() {
     relative_from: Some("")
     );
 
+    tc!("foo/.//bar", "foo/bar",
+    eq: true,
+    starts_with: true,
+    ends_with: true,
+    relative_from: Some("")
+    );
+
+    tc!("foo//./bar", "foo/bar",
+    eq: true,
+    starts_with: true,
+    ends_with: true,
+    relative_from: Some("")
+    );
+
     tc!("foo/bar", "foo",
     eq: false,
     starts_with: true,
@@ -1566,6 +1668,13 @@ pub fn test_compare() {
     relative_from: Some("bar")
     );
 
+    tc!("foo/bar", "foobar",
+    eq: false,
+    starts_with: false,
+    ends_with: false,
+    relative_from: None
+    );
+
     tc!("foo/bar/baz", "foo/bar",
     eq: false,
     starts_with: true,
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index f52b9e52c54..fe243550606 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -80,14 +80,21 @@ use crate::sync::Once;
 /// static LIST: OnceList<u32> = OnceList::new();
 /// static COUNTER: AtomicU32 = AtomicU32::new(0);
 ///
-/// let vec = (0..thread::available_parallelism().unwrap().get()).map(|_| thread::spawn(|| {
-///     while let i @ 0..=1000 = COUNTER.fetch_add(1, Ordering::Relaxed) {
-///         LIST.push(i);
+/// # const LEN: u32 = if cfg!(miri) { 50 } else { 1000 };
+/// # /*
+/// const LEN: u32 = 1000;
+/// # */
+/// thread::scope(|s| {
+///     for _ in 0..thread::available_parallelism().unwrap().get() {
+///         s.spawn(|| {
+///             while let i @ 0..LEN = COUNTER.fetch_add(1, Ordering::Relaxed) {
+///                 LIST.push(i);
+///             }
+///         });
 ///     }
-/// })).collect::<Vec<thread::JoinHandle<_>>>();
-/// vec.into_iter().for_each(|handle| handle.join().unwrap());
+/// });
 ///
-/// for i in 0..=1000 {
+/// for i in 0..LEN {
 ///     assert!(LIST.contains(&i));
 /// }
 ///
diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs
index db2ec73148e..e2ec838b740 100644
--- a/library/std/src/sys/pal/unix/args.rs
+++ b/library/std/src/sys/pal/unix/args.rs
@@ -183,7 +183,7 @@ mod imp {
 // Use `_NSGetArgc` and `_NSGetArgv` on Apple platforms.
 //
 // Even though these have underscores in their names, they've been available
-// since since the first versions of both macOS and iOS, and are declared in
+// since the first versions of both macOS and iOS, and are declared in
 // the header `crt_externs.h`.
 //
 // NOTE: This header was added to the iOS 13.0 SDK, which has been the source
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index 92c76ec4303..f9d6b5fbc86 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -1976,13 +1976,14 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
 
 pub use remove_dir_impl::remove_dir_all;
 
-// Fallback for REDOX, ESP-ID, Horizon, Vita and Miri
+// Fallback for REDOX, ESP-ID, Horizon, Vita, Vxworks and Miri
 #[cfg(any(
     target_os = "redox",
     target_os = "espidf",
     target_os = "horizon",
     target_os = "vita",
     target_os = "nto",
+    target_os = "vxworks",
     miri
 ))]
 mod remove_dir_impl {
@@ -1996,6 +1997,7 @@ mod remove_dir_impl {
     target_os = "horizon",
     target_os = "vita",
     target_os = "nto",
+    target_os = "vxworks",
     miri
 )))]
 mod remove_dir_impl {
diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs
index 76179e0910d..5007dbd34b4 100644
--- a/library/std/src/sys/pal/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs
@@ -1,5 +1,5 @@
 use crate::fmt;
-use crate::io::{self, Error, ErrorKind};
+use crate::io::{self, ErrorKind};
 use crate::num::NonZero;
 use crate::sys;
 use crate::sys::cvt;
diff --git a/library/std/src/sys/pal/wasm/atomics/futex.rs b/library/std/src/sys/pal/wasm/atomics/futex.rs
index f4fbe9f4855..a21b71efbbc 100644
--- a/library/std/src/sys/pal/wasm/atomics/futex.rs
+++ b/library/std/src/sys/pal/wasm/atomics/futex.rs
@@ -1,4 +1,8 @@
-use crate::arch::wasm32;
+#[cfg(target_arch = "wasm32")]
+use core::arch::wasm32 as wasm;
+#[cfg(target_arch = "wasm64")]
+use core::arch::wasm64 as wasm;
+
 use crate::sync::atomic::AtomicU32;
 use crate::time::Duration;
 
@@ -10,11 +14,8 @@ use crate::time::Duration;
 pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
     let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1);
     unsafe {
-        wasm32::memory_atomic_wait32(
-            futex as *const AtomicU32 as *mut i32,
-            expected as i32,
-            timeout,
-        ) < 2
+        wasm::memory_atomic_wait32(futex as *const AtomicU32 as *mut i32, expected as i32, timeout)
+            < 2
     }
 }
 
@@ -23,12 +24,12 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
 /// Returns true if this actually woke up such a thread,
 /// or false if no thread was waiting on this futex.
 pub fn futex_wake(futex: &AtomicU32) -> bool {
-    unsafe { wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 }
+    unsafe { wasm::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 }
 }
 
 /// Wake up all threads that are waiting on futex_wait on this futex.
 pub fn futex_wake_all(futex: &AtomicU32) {
     unsafe {
-        wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32);
+        wasm::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32);
     }
 }
diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs
index 484bd08495e..afdb159fe6f 100644
--- a/library/std/src/sys/pal/wasm/atomics/thread.rs
+++ b/library/std/src/sys/pal/wasm/atomics/thread.rs
@@ -19,7 +19,11 @@ impl Thread {
     pub fn set_name(_name: &CStr) {}
 
     pub fn sleep(dur: Duration) {
-        use crate::arch::wasm32;
+        #[cfg(target_arch = "wasm32")]
+        use core::arch::wasm32 as wasm;
+        #[cfg(target_arch = "wasm64")]
+        use core::arch::wasm64 as wasm;
+
         use crate::cmp;
 
         // Use an atomic wait to block the current thread artificially with a
@@ -31,7 +35,7 @@ impl Thread {
         while nanos > 0 {
             let amt = cmp::min(i64::MAX as u128, nanos);
             let mut x = 0;
-            let val = unsafe { wasm32::memory_atomic_wait32(&mut x, 0, amt as i64) };
+            let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) };
             debug_assert_eq!(val, 2);
             nanos -= amt;
         }
diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs
index 681d1a5efe9..24c237b5eb0 100644
--- a/library/std/src/sys/pal/windows/alloc.rs
+++ b/library/std/src/sys/pal/windows/alloc.rs
@@ -190,7 +190,7 @@ unsafe fn allocate(layout: Layout, zeroed: bool) -> *mut u8 {
         // it, it is safe to write a header directly before it.
         unsafe { ptr::write((aligned as *mut Header).sub(1), Header(ptr)) };
 
-        // SAFETY: The returned pointer does not point to the to the start of an allocated block,
+        // SAFETY: The returned pointer does not point to the start of an allocated block,
         // but there is a header readable directly before it containing the location of the start
         // of the block.
         aligned
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index 6ec82693077..27aa35f69f1 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -13,6 +13,8 @@ use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort, c_vo
 use crate::os::windows::io::{AsRawHandle, BorrowedHandle};
 use crate::ptr;
 
+mod windows_targets;
+
 mod windows_sys;
 pub use windows_sys::*;
 
@@ -504,11 +506,8 @@ if #[cfg(not(target_vendor = "uwp"))] {
     #[cfg(target_arch = "arm")]
     pub enum CONTEXT {}
 }}
-
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32;
-}
+// WSAStartup is only redefined here so that we can override WSADATA for Arm32
+windows_targets::link!("ws2_32.dll" "system" fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32);
 #[cfg(target_arch = "arm")]
 #[repr(C)]
 pub struct WSADATA {
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index 849e64ac591..5ad4a3731d8 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -1,5 +1,5 @@
 --out windows_sys.rs
---config flatten std
+--config flatten sys
 --filter
 !Windows.Win32.Foundation.INVALID_HANDLE_VALUE
 Windows.Wdk.Storage.FileSystem.FILE_COMPLETE_IF_OPLOCKED
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index 19f013d3347..fea00fec9ae 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -1,843 +1,136 @@
-// Bindings generated by `windows-bindgen` 0.57.0
+// Bindings generated by `windows-bindgen` 0.58.0
 
 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
-#[link(name = "advapi32")]
-extern "system" {
-    pub fn OpenProcessToken(
-        processhandle: HANDLE,
-        desiredaccess: TOKEN_ACCESS_MASK,
-        tokenhandle: *mut HANDLE,
-    ) -> BOOL;
-}
-#[link(name = "advapi32")]
-extern "system" {
-    #[link_name = "SystemFunction036"]
-    pub fn RtlGenRandom(randombuffer: *mut core::ffi::c_void, randombufferlength: u32) -> BOOLEAN;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn AcquireSRWLockExclusive(srwlock: *mut SRWLOCK);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn AcquireSRWLockShared(srwlock: *mut SRWLOCK);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CancelIo(hfile: HANDLE) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CloseHandle(hobject: HANDLE) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CompareStringOrdinal(
-        lpstring1: PCWSTR,
-        cchcount1: i32,
-        lpstring2: PCWSTR,
-        cchcount2: i32,
-        bignorecase: BOOL,
-    ) -> COMPARESTRING_RESULT;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CopyFileExW(
-        lpexistingfilename: PCWSTR,
-        lpnewfilename: PCWSTR,
-        lpprogressroutine: LPPROGRESS_ROUTINE,
-        lpdata: *const core::ffi::c_void,
-        pbcancel: *mut BOOL,
-        dwcopyflags: u32,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CreateDirectoryW(
-        lppathname: PCWSTR,
-        lpsecurityattributes: *const SECURITY_ATTRIBUTES,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CreateEventW(
-        lpeventattributes: *const SECURITY_ATTRIBUTES,
-        bmanualreset: BOOL,
-        binitialstate: BOOL,
-        lpname: PCWSTR,
-    ) -> HANDLE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CreateFileW(
-        lpfilename: PCWSTR,
-        dwdesiredaccess: u32,
-        dwsharemode: FILE_SHARE_MODE,
-        lpsecurityattributes: *const SECURITY_ATTRIBUTES,
-        dwcreationdisposition: FILE_CREATION_DISPOSITION,
-        dwflagsandattributes: FILE_FLAGS_AND_ATTRIBUTES,
-        htemplatefile: HANDLE,
-    ) -> HANDLE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CreateHardLinkW(
-        lpfilename: PCWSTR,
-        lpexistingfilename: PCWSTR,
-        lpsecurityattributes: *const SECURITY_ATTRIBUTES,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CreateNamedPipeW(
-        lpname: PCWSTR,
-        dwopenmode: FILE_FLAGS_AND_ATTRIBUTES,
-        dwpipemode: NAMED_PIPE_MODE,
-        nmaxinstances: u32,
-        noutbuffersize: u32,
-        ninbuffersize: u32,
-        ndefaulttimeout: u32,
-        lpsecurityattributes: *const SECURITY_ATTRIBUTES,
-    ) -> HANDLE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CreateProcessW(
-        lpapplicationname: PCWSTR,
-        lpcommandline: PWSTR,
-        lpprocessattributes: *const SECURITY_ATTRIBUTES,
-        lpthreadattributes: *const SECURITY_ATTRIBUTES,
-        binherithandles: BOOL,
-        dwcreationflags: PROCESS_CREATION_FLAGS,
-        lpenvironment: *const core::ffi::c_void,
-        lpcurrentdirectory: PCWSTR,
-        lpstartupinfo: *const STARTUPINFOW,
-        lpprocessinformation: *mut PROCESS_INFORMATION,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CreateSymbolicLinkW(
-        lpsymlinkfilename: PCWSTR,
-        lptargetfilename: PCWSTR,
-        dwflags: SYMBOLIC_LINK_FLAGS,
-    ) -> BOOLEAN;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CreateThread(
-        lpthreadattributes: *const SECURITY_ATTRIBUTES,
-        dwstacksize: usize,
-        lpstartaddress: LPTHREAD_START_ROUTINE,
-        lpparameter: *const core::ffi::c_void,
-        dwcreationflags: THREAD_CREATION_FLAGS,
-        lpthreadid: *mut u32,
-    ) -> HANDLE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn CreateWaitableTimerExW(
-        lptimerattributes: *const SECURITY_ATTRIBUTES,
-        lptimername: PCWSTR,
-        dwflags: u32,
-        dwdesiredaccess: u32,
-    ) -> HANDLE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn DeleteProcThreadAttributeList(lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn DeviceIoControl(
-        hdevice: HANDLE,
-        dwiocontrolcode: u32,
-        lpinbuffer: *const core::ffi::c_void,
-        ninbuffersize: u32,
-        lpoutbuffer: *mut core::ffi::c_void,
-        noutbuffersize: u32,
-        lpbytesreturned: *mut u32,
-        lpoverlapped: *mut OVERLAPPED,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn DuplicateHandle(
-        hsourceprocesshandle: HANDLE,
-        hsourcehandle: HANDLE,
-        htargetprocesshandle: HANDLE,
-        lptargethandle: *mut HANDLE,
-        dwdesiredaccess: u32,
-        binherithandle: BOOL,
-        dwoptions: DUPLICATE_HANDLE_OPTIONS,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn ExitProcess(uexitcode: u32) -> !;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn FindClose(hfindfile: HANDLE) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn FindFirstFileW(lpfilename: PCWSTR, lpfindfiledata: *mut WIN32_FIND_DATAW) -> HANDLE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn FindNextFileW(hfindfile: HANDLE, lpfindfiledata: *mut WIN32_FIND_DATAW) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn FlushFileBuffers(hfile: HANDLE) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn FormatMessageW(
-        dwflags: FORMAT_MESSAGE_OPTIONS,
-        lpsource: *const core::ffi::c_void,
-        dwmessageid: u32,
-        dwlanguageid: u32,
-        lpbuffer: PWSTR,
-        nsize: u32,
-        arguments: *const *const i8,
-    ) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn FreeEnvironmentStringsW(penv: PCWSTR) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetActiveProcessorCount(groupnumber: u16) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetCommandLineW() -> PCWSTR;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetConsoleMode(hconsolehandle: HANDLE, lpmode: *mut CONSOLE_MODE) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetCurrentDirectoryW(nbufferlength: u32, lpbuffer: PWSTR) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetCurrentProcess() -> HANDLE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetCurrentProcessId() -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetCurrentThread() -> HANDLE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetEnvironmentStringsW() -> PWSTR;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetEnvironmentVariableW(lpname: PCWSTR, lpbuffer: PWSTR, nsize: u32) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetExitCodeProcess(hprocess: HANDLE, lpexitcode: *mut u32) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetFileAttributesW(lpfilename: PCWSTR) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetFileInformationByHandle(
-        hfile: HANDLE,
-        lpfileinformation: *mut BY_HANDLE_FILE_INFORMATION,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetFileInformationByHandleEx(
-        hfile: HANDLE,
-        fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
-        lpfileinformation: *mut core::ffi::c_void,
-        dwbuffersize: u32,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetFileType(hfile: HANDLE) -> FILE_TYPE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetFinalPathNameByHandleW(
-        hfile: HANDLE,
-        lpszfilepath: PWSTR,
-        cchfilepath: u32,
-        dwflags: GETFINALPATHNAMEBYHANDLE_FLAGS,
-    ) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetFullPathNameW(
-        lpfilename: PCWSTR,
-        nbufferlength: u32,
-        lpbuffer: PWSTR,
-        lpfilepart: *mut PWSTR,
-    ) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetLastError() -> WIN32_ERROR;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetModuleFileNameW(hmodule: HMODULE, lpfilename: PWSTR, nsize: u32) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetModuleHandleA(lpmodulename: PCSTR) -> HMODULE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetModuleHandleW(lpmodulename: PCWSTR) -> HMODULE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetOverlappedResult(
-        hfile: HANDLE,
-        lpoverlapped: *const OVERLAPPED,
-        lpnumberofbytestransferred: *mut u32,
-        bwait: BOOL,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetProcessId(process: HANDLE) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetStdHandle(nstdhandle: STD_HANDLE) -> HANDLE;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetSystemDirectoryW(lpbuffer: PWSTR, usize: u32) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetSystemInfo(lpsysteminfo: *mut SYSTEM_INFO);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime: *mut FILETIME);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetTempPathW(nbufferlength: u32, lpbuffer: PWSTR) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn GetWindowsDirectoryW(lpbuffer: PWSTR, usize: u32) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn InitOnceBeginInitialize(
-        lpinitonce: *mut INIT_ONCE,
-        dwflags: u32,
-        fpending: *mut BOOL,
-        lpcontext: *mut *mut core::ffi::c_void,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn InitOnceComplete(
-        lpinitonce: *mut INIT_ONCE,
-        dwflags: u32,
-        lpcontext: *const core::ffi::c_void,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn InitializeProcThreadAttributeList(
-        lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
-        dwattributecount: u32,
-        dwflags: u32,
-        lpsize: *mut usize,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn LocalFree(hmem: HLOCAL) -> HLOCAL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn MoveFileExW(
-        lpexistingfilename: PCWSTR,
-        lpnewfilename: PCWSTR,
-        dwflags: MOVE_FILE_FLAGS,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn MultiByteToWideChar(
-        codepage: u32,
-        dwflags: MULTI_BYTE_TO_WIDE_CHAR_FLAGS,
-        lpmultibytestr: PCSTR,
-        cbmultibyte: i32,
-        lpwidecharstr: PWSTR,
-        cchwidechar: i32,
-    ) -> i32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn QueryPerformanceCounter(lpperformancecount: *mut i64) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn QueryPerformanceFrequency(lpfrequency: *mut i64) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn ReadConsoleW(
-        hconsoleinput: HANDLE,
-        lpbuffer: *mut core::ffi::c_void,
-        nnumberofcharstoread: u32,
-        lpnumberofcharsread: *mut u32,
-        pinputcontrol: *const CONSOLE_READCONSOLE_CONTROL,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn ReadFile(
-        hfile: HANDLE,
-        lpbuffer: *mut u8,
-        nnumberofbytestoread: u32,
-        lpnumberofbytesread: *mut u32,
-        lpoverlapped: *mut OVERLAPPED,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn ReadFileEx(
-        hfile: HANDLE,
-        lpbuffer: *mut u8,
-        nnumberofbytestoread: u32,
-        lpoverlapped: *mut OVERLAPPED,
-        lpcompletionroutine: LPOVERLAPPED_COMPLETION_ROUTINE,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn ReleaseSRWLockExclusive(srwlock: *mut SRWLOCK);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn ReleaseSRWLockShared(srwlock: *mut SRWLOCK);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn RemoveDirectoryW(lppathname: PCWSTR) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetCurrentDirectoryW(lppathname: PCWSTR) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetEnvironmentVariableW(lpname: PCWSTR, lpvalue: PCWSTR) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetFileAttributesW(
-        lpfilename: PCWSTR,
-        dwfileattributes: FILE_FLAGS_AND_ATTRIBUTES,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetFileInformationByHandle(
-        hfile: HANDLE,
-        fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
-        lpfileinformation: *const core::ffi::c_void,
-        dwbuffersize: u32,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetFilePointerEx(
-        hfile: HANDLE,
-        lidistancetomove: i64,
-        lpnewfilepointer: *mut i64,
-        dwmovemethod: SET_FILE_POINTER_MOVE_METHOD,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetFileTime(
-        hfile: HANDLE,
-        lpcreationtime: *const FILETIME,
-        lplastaccesstime: *const FILETIME,
-        lplastwritetime: *const FILETIME,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetHandleInformation(hobject: HANDLE, dwmask: u32, dwflags: HANDLE_FLAGS) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetLastError(dwerrcode: WIN32_ERROR);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SetWaitableTimer(
-        htimer: HANDLE,
-        lpduetime: *const i64,
-        lperiod: i32,
-        pfncompletionroutine: PTIMERAPCROUTINE,
-        lpargtocompletionroutine: *const core::ffi::c_void,
-        fresume: BOOL,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn Sleep(dwmilliseconds: u32);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SleepConditionVariableSRW(
-        conditionvariable: *mut CONDITION_VARIABLE,
-        srwlock: *mut SRWLOCK,
-        dwmilliseconds: u32,
-        flags: u32,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SleepEx(dwmilliseconds: u32, balertable: BOOL) -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn SwitchToThread() -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn TerminateProcess(hprocess: HANDLE, uexitcode: u32) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn TlsAlloc() -> u32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn TlsFree(dwtlsindex: u32) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn TlsGetValue(dwtlsindex: u32) -> *mut core::ffi::c_void;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn TlsSetValue(dwtlsindex: u32, lptlsvalue: *const core::ffi::c_void) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn TryAcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> BOOLEAN;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn TryAcquireSRWLockShared(srwlock: *mut SRWLOCK) -> BOOLEAN;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn UpdateProcThreadAttribute(
-        lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
-        dwflags: u32,
-        attribute: usize,
-        lpvalue: *const core::ffi::c_void,
-        cbsize: usize,
-        lppreviousvalue: *mut core::ffi::c_void,
-        lpreturnsize: *const usize,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn WaitForMultipleObjects(
-        ncount: u32,
-        lphandles: *const HANDLE,
-        bwaitall: BOOL,
-        dwmilliseconds: u32,
-    ) -> WAIT_EVENT;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> WAIT_EVENT;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn WakeAllConditionVariable(conditionvariable: *mut CONDITION_VARIABLE);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn WakeConditionVariable(conditionvariable: *mut CONDITION_VARIABLE);
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn WideCharToMultiByte(
-        codepage: u32,
-        dwflags: u32,
-        lpwidecharstr: PCWSTR,
-        cchwidechar: i32,
-        lpmultibytestr: PSTR,
-        cbmultibyte: i32,
-        lpdefaultchar: PCSTR,
-        lpuseddefaultchar: *mut BOOL,
-    ) -> i32;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn WriteConsoleW(
-        hconsoleoutput: HANDLE,
-        lpbuffer: *const core::ffi::c_void,
-        nnumberofcharstowrite: u32,
-        lpnumberofcharswritten: *mut u32,
-        lpreserved: *const core::ffi::c_void,
-    ) -> BOOL;
-}
-#[link(name = "kernel32")]
-extern "system" {
-    pub fn WriteFileEx(
-        hfile: HANDLE,
-        lpbuffer: *const u8,
-        nnumberofbytestowrite: u32,
-        lpoverlapped: *mut OVERLAPPED,
-        lpcompletionroutine: LPOVERLAPPED_COMPLETION_ROUTINE,
-    ) -> BOOL;
-}
-#[link(name = "ntdll")]
-extern "system" {
-    pub fn NtCreateFile(
-        filehandle: *mut HANDLE,
-        desiredaccess: FILE_ACCESS_RIGHTS,
-        objectattributes: *const OBJECT_ATTRIBUTES,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        allocationsize: *const i64,
-        fileattributes: FILE_FLAGS_AND_ATTRIBUTES,
-        shareaccess: FILE_SHARE_MODE,
-        createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
-        createoptions: NTCREATEFILE_CREATE_OPTIONS,
-        eabuffer: *const core::ffi::c_void,
-        ealength: u32,
-    ) -> NTSTATUS;
-}
-#[link(name = "ntdll")]
-extern "system" {
-    pub fn NtReadFile(
-        filehandle: HANDLE,
-        event: HANDLE,
-        apcroutine: PIO_APC_ROUTINE,
-        apccontext: *const core::ffi::c_void,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        buffer: *mut core::ffi::c_void,
-        length: u32,
-        byteoffset: *const i64,
-        key: *const u32,
-    ) -> NTSTATUS;
-}
-#[link(name = "ntdll")]
-extern "system" {
-    pub fn NtWriteFile(
-        filehandle: HANDLE,
-        event: HANDLE,
-        apcroutine: PIO_APC_ROUTINE,
-        apccontext: *const core::ffi::c_void,
-        iostatusblock: *mut IO_STATUS_BLOCK,
-        buffer: *const core::ffi::c_void,
-        length: u32,
-        byteoffset: *const i64,
-        key: *const u32,
-    ) -> NTSTATUS;
-}
-#[link(name = "ntdll")]
-extern "system" {
-    pub fn RtlNtStatusToDosError(status: NTSTATUS) -> u32;
-}
-#[link(name = "userenv")]
-extern "system" {
-    pub fn GetUserProfileDirectoryW(
-        htoken: HANDLE,
-        lpprofiledir: PWSTR,
-        lpcchsize: *mut u32,
-    ) -> BOOL;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn WSACleanup() -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn WSADuplicateSocketW(
-        s: SOCKET,
-        dwprocessid: u32,
-        lpprotocolinfo: *mut WSAPROTOCOL_INFOW,
-    ) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn WSAGetLastError() -> WSA_ERROR;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn WSARecv(
-        s: SOCKET,
-        lpbuffers: *const WSABUF,
-        dwbuffercount: u32,
-        lpnumberofbytesrecvd: *mut u32,
-        lpflags: *mut u32,
-        lpoverlapped: *mut OVERLAPPED,
-        lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
-    ) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn WSASend(
-        s: SOCKET,
-        lpbuffers: *const WSABUF,
-        dwbuffercount: u32,
-        lpnumberofbytessent: *mut u32,
-        dwflags: u32,
-        lpoverlapped: *mut OVERLAPPED,
-        lpcompletionroutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
-    ) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn WSASocketW(
-        af: i32,
-        r#type: i32,
-        protocol: i32,
-        lpprotocolinfo: *const WSAPROTOCOL_INFOW,
-        g: u32,
-        dwflags: u32,
-    ) -> SOCKET;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn accept(s: SOCKET, addr: *mut SOCKADDR, addrlen: *mut i32) -> SOCKET;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn bind(s: SOCKET, name: *const SOCKADDR, namelen: i32) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn closesocket(s: SOCKET) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn connect(s: SOCKET, name: *const SOCKADDR, namelen: i32) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn freeaddrinfo(paddrinfo: *const ADDRINFOA);
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn getaddrinfo(
-        pnodename: PCSTR,
-        pservicename: PCSTR,
-        phints: *const ADDRINFOA,
-        ppresult: *mut *mut ADDRINFOA,
-    ) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn getpeername(s: SOCKET, name: *mut SOCKADDR, namelen: *mut i32) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn getsockname(s: SOCKET, name: *mut SOCKADDR, namelen: *mut i32) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn getsockopt(s: SOCKET, level: i32, optname: i32, optval: PSTR, optlen: *mut i32) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn ioctlsocket(s: SOCKET, cmd: i32, argp: *mut u32) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn listen(s: SOCKET, backlog: i32) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn recv(s: SOCKET, buf: PSTR, len: i32, flags: SEND_RECV_FLAGS) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn recvfrom(
-        s: SOCKET,
-        buf: PSTR,
-        len: i32,
-        flags: i32,
-        from: *mut SOCKADDR,
-        fromlen: *mut i32,
-    ) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn select(
-        nfds: i32,
-        readfds: *mut FD_SET,
-        writefds: *mut FD_SET,
-        exceptfds: *mut FD_SET,
-        timeout: *const TIMEVAL,
-    ) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn send(s: SOCKET, buf: PCSTR, len: i32, flags: SEND_RECV_FLAGS) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn sendto(
-        s: SOCKET,
-        buf: PCSTR,
-        len: i32,
-        flags: i32,
-        to: *const SOCKADDR,
-        tolen: i32,
-    ) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn setsockopt(s: SOCKET, level: i32, optname: i32, optval: PCSTR, optlen: i32) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn shutdown(s: SOCKET, how: WINSOCK_SHUTDOWN_HOW) -> i32;
-}
+windows_targets::link!("advapi32.dll" "system" fn OpenProcessToken(processhandle : HANDLE, desiredaccess : TOKEN_ACCESS_MASK, tokenhandle : *mut HANDLE) -> BOOL);
+windows_targets::link!("advapi32.dll" "system" "SystemFunction036" fn RtlGenRandom(randombuffer : *mut core::ffi::c_void, randombufferlength : u32) -> BOOLEAN);
+windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockExclusive(srwlock : *mut SRWLOCK));
+windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockShared(srwlock : *mut SRWLOCK));
+windows_targets::link!("kernel32.dll" "system" fn CancelIo(hfile : HANDLE) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn CompareStringOrdinal(lpstring1 : PCWSTR, cchcount1 : i32, lpstring2 : PCWSTR, cchcount2 : i32, bignorecase : BOOL) -> COMPARESTRING_RESULT);
+windows_targets::link!("kernel32.dll" "system" fn CopyFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, lpprogressroutine : LPPROGRESS_ROUTINE, lpdata : *const core::ffi::c_void, pbcancel : *mut BOOL, dwcopyflags : u32) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn CreateDirectoryW(lppathname : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn CreateFileW(lpfilename : PCWSTR, dwdesiredaccess : u32, dwsharemode : FILE_SHARE_MODE, lpsecurityattributes : *const SECURITY_ATTRIBUTES, dwcreationdisposition : FILE_CREATION_DISPOSITION, dwflagsandattributes : FILE_FLAGS_AND_ATTRIBUTES, htemplatefile : HANDLE) -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn CreateHardLinkW(lpfilename : PCWSTR, lpexistingfilename : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn CreateNamedPipeW(lpname : PCWSTR, dwopenmode : FILE_FLAGS_AND_ATTRIBUTES, dwpipemode : NAMED_PIPE_MODE, nmaxinstances : u32, noutbuffersize : u32, ninbuffersize : u32, ndefaulttimeout : u32, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn CreateProcessW(lpapplicationname : PCWSTR, lpcommandline : PWSTR, lpprocessattributes : *const SECURITY_ATTRIBUTES, lpthreadattributes : *const SECURITY_ATTRIBUTES, binherithandles : BOOL, dwcreationflags : PROCESS_CREATION_FLAGS, lpenvironment : *const core::ffi::c_void, lpcurrentdirectory : PCWSTR, lpstartupinfo : *const STARTUPINFOW, lpprocessinformation : *mut PROCESS_INFORMATION) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn CreateSymbolicLinkW(lpsymlinkfilename : PCWSTR, lptargetfilename : PCWSTR, dwflags : SYMBOLIC_LINK_FLAGS) -> BOOLEAN);
+windows_targets::link!("kernel32.dll" "system" fn CreateThread(lpthreadattributes : *const SECURITY_ATTRIBUTES, dwstacksize : usize, lpstartaddress : LPTHREAD_START_ROUTINE, lpparameter : *const core::ffi::c_void, dwcreationflags : THREAD_CREATION_FLAGS, lpthreadid : *mut u32) -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn CreateWaitableTimerExW(lptimerattributes : *const SECURITY_ATTRIBUTES, lptimername : PCWSTR, dwflags : u32, dwdesiredaccess : u32) -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn DeleteFileW(lpfilename : PCWSTR) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn DeleteProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST));
+windows_targets::link!("kernel32.dll" "system" fn DeviceIoControl(hdevice : HANDLE, dwiocontrolcode : u32, lpinbuffer : *const core::ffi::c_void, ninbuffersize : u32, lpoutbuffer : *mut core::ffi::c_void, noutbuffersize : u32, lpbytesreturned : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn DuplicateHandle(hsourceprocesshandle : HANDLE, hsourcehandle : HANDLE, htargetprocesshandle : HANDLE, lptargethandle : *mut HANDLE, dwdesiredaccess : u32, binherithandle : BOOL, dwoptions : DUPLICATE_HANDLE_OPTIONS) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn ExitProcess(uexitcode : u32) -> !);
+windows_targets::link!("kernel32.dll" "system" fn FindClose(hfindfile : HANDLE) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn FindFirstFileW(lpfilename : PCWSTR, lpfindfiledata : *mut WIN32_FIND_DATAW) -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn FindNextFileW(hfindfile : HANDLE, lpfindfiledata : *mut WIN32_FIND_DATAW) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn FlushFileBuffers(hfile : HANDLE) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn FreeEnvironmentStringsW(penv : PCWSTR) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn GetActiveProcessorCount(groupnumber : u16) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetCommandLineW() -> PCWSTR);
+windows_targets::link!("kernel32.dll" "system" fn GetConsoleMode(hconsolehandle : HANDLE, lpmode : *mut CONSOLE_MODE) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn GetCurrentDirectoryW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcess() -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcessId() -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetCurrentThread() -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentStringsW() -> PWSTR);
+windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentVariableW(lpname : PCWSTR, lpbuffer : PWSTR, nsize : u32) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : HANDLE, lpexitcode : *mut u32) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn GetFileAttributesW(lpfilename : PCWSTR) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandle(hfile : HANDLE, lpfileinformation : *mut BY_HANDLE_FILE_INFORMATION) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandleEx(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *mut core::ffi::c_void, dwbuffersize : u32) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE);
+windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR);
+windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(hmodule : HMODULE, lpfilename : PWSTR, nsize : u32) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleA(lpmodulename : PCSTR) -> HMODULE);
+windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleW(lpmodulename : PCWSTR) -> HMODULE);
+windows_targets::link!("kernel32.dll" "system" fn GetOverlappedResult(hfile : HANDLE, lpoverlapped : *const OVERLAPPED, lpnumberofbytestransferred : *mut u32, bwait : BOOL) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC);
+windows_targets::link!("kernel32.dll" "system" fn GetProcessId(process : HANDLE) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetStdHandle(nstdhandle : STD_HANDLE) -> HANDLE);
+windows_targets::link!("kernel32.dll" "system" fn GetSystemDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : *mut SYSTEM_INFO));
+windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
+windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
+windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL);
+windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32);
+windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceFrequency(lpfrequency : *mut i64) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn ReadConsoleW(hconsoleinput : HANDLE, lpbuffer : *mut core::ffi::c_void, nnumberofcharstoread : u32, lpnumberofcharsread : *mut u32, pinputcontrol : *const CONSOLE_READCONSOLE_CONTROL) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn ReadFile(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpnumberofbytesread : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn ReadFileEx(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockExclusive(srwlock : *mut SRWLOCK));
+windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockShared(srwlock : *mut SRWLOCK));
+windows_targets::link!("kernel32.dll" "system" fn RemoveDirectoryW(lppathname : PCWSTR) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SetCurrentDirectoryW(lppathname : PCWSTR) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SetEnvironmentVariableW(lpname : PCWSTR, lpvalue : PCWSTR) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SetFileAttributesW(lpfilename : PCWSTR, dwfileattributes : FILE_FLAGS_AND_ATTRIBUTES) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SetFileInformationByHandle(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *const core::ffi::c_void, dwbuffersize : u32) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, lidistancetomove : i64, lpnewfilepointer : *mut i64, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SetLastError(dwerrcode : WIN32_ERROR));
+windows_targets::link!("kernel32.dll" "system" fn SetThreadStackGuarantee(stacksizeinbytes : *mut u32) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SetWaitableTimer(htimer : HANDLE, lpduetime : *const i64, lperiod : i32, pfncompletionroutine : PTIMERAPCROUTINE, lpargtocompletionroutine : *const core::ffi::c_void, fresume : BOOL) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32));
+windows_targets::link!("kernel32.dll" "system" fn SleepConditionVariableSRW(conditionvariable : *mut CONDITION_VARIABLE, srwlock : *mut SRWLOCK, dwmilliseconds : u32, flags : u32) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn SleepEx(dwmilliseconds : u32, balertable : BOOL) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn SwitchToThread() -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn TerminateProcess(hprocess : HANDLE, uexitcode : u32) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn TlsAlloc() -> u32);
+windows_targets::link!("kernel32.dll" "system" fn TlsFree(dwtlsindex : u32) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32) -> *mut core::ffi::c_void);
+windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> BOOLEAN);
+windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> BOOLEAN);
+windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT);
+windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT);
+windows_targets::link!("kernel32.dll" "system" fn WakeAllConditionVariable(conditionvariable : *mut CONDITION_VARIABLE));
+windows_targets::link!("kernel32.dll" "system" fn WakeConditionVariable(conditionvariable : *mut CONDITION_VARIABLE));
+windows_targets::link!("kernel32.dll" "system" fn WideCharToMultiByte(codepage : u32, dwflags : u32, lpwidecharstr : PCWSTR, cchwidechar : i32, lpmultibytestr : PSTR, cbmultibyte : i32, lpdefaultchar : PCSTR, lpuseddefaultchar : *mut BOOL) -> i32);
+windows_targets::link!("kernel32.dll" "system" fn WriteConsoleW(hconsoleoutput : HANDLE, lpbuffer : PCWSTR, nnumberofcharstowrite : u32, lpnumberofcharswritten : *mut u32, lpreserved : *const core::ffi::c_void) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn WriteFileEx(hfile : HANDLE, lpbuffer : *const u8, nnumberofbytestowrite : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL);
+windows_targets::link!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
+windows_targets::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
+windows_targets::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
+windows_targets::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
+windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL);
+windows_targets::link!("ws2_32.dll" "system" fn WSACleanup() -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn WSADuplicateSocketW(s : SOCKET, dwprocessid : u32, lpprotocolinfo : *mut WSAPROTOCOL_INFOW) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn WSAGetLastError() -> WSA_ERROR);
+windows_targets::link!("ws2_32.dll" "system" fn WSARecv(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytesrecvd : *mut u32, lpflags : *mut u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn WSASend(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytessent : *mut u32, dwflags : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn WSASocketW(af : i32, r#type : i32, protocol : i32, lpprotocolinfo : *const WSAPROTOCOL_INFOW, g : u32, dwflags : u32) -> SOCKET);
+windows_targets::link!("ws2_32.dll" "system" fn accept(s : SOCKET, addr : *mut SOCKADDR, addrlen : *mut i32) -> SOCKET);
+windows_targets::link!("ws2_32.dll" "system" fn bind(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn closesocket(s : SOCKET) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn connect(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn freeaddrinfo(paddrinfo : *const ADDRINFOA));
+windows_targets::link!("ws2_32.dll" "system" fn getaddrinfo(pnodename : PCSTR, pservicename : PCSTR, phints : *const ADDRINFOA, ppresult : *mut *mut ADDRINFOA) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn getpeername(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn getsockname(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn getsockopt(s : SOCKET, level : i32, optname : i32, optval : PSTR, optlen : *mut i32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn ioctlsocket(s : SOCKET, cmd : i32, argp : *mut u32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn listen(s : SOCKET, backlog : i32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn recv(s : SOCKET, buf : PSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn recvfrom(s : SOCKET, buf : PSTR, len : i32, flags : i32, from : *mut SOCKADDR, fromlen : *mut i32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn select(nfds : i32, readfds : *mut FD_SET, writefds : *mut FD_SET, exceptfds : *mut FD_SET, timeout : *const TIMEVAL) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn send(s : SOCKET, buf : PCSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn sendto(s : SOCKET, buf : PCSTR, len : i32, flags : i32, to : *const SOCKADDR, tolen : i32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn setsockopt(s : SOCKET, level : i32, optname : i32, optval : PCSTR, optlen : i32) -> i32);
+windows_targets::link!("ws2_32.dll" "system" fn shutdown(s : SOCKET, how : WINSOCK_SHUTDOWN_HOW) -> i32);
 pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32;
 pub type ADDRESS_FAMILY = u16;
 #[repr(C)]
@@ -3991,3 +3284,4 @@ pub struct XSAVE_FORMAT {
     pub Reserved4: [u8; 224],
 }
 // ignore-tidy-filelength
+use super::windows_targets;
diff --git a/library/std/src/sys/pal/windows/c/windows_targets.rs b/library/std/src/sys/pal/windows/c/windows_targets.rs
new file mode 100644
index 00000000000..56c563462d3
--- /dev/null
+++ b/library/std/src/sys/pal/windows/c/windows_targets.rs
@@ -0,0 +1,24 @@
+//! Provides the `link!` macro used by the generated windows bindings.
+//!
+//! This is a simple wrapper around an `extern` block with a `#[link]` attribute.
+//! It's very roughly equivalent to the windows-targets crate.
+
+pub macro link {
+    ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
+        // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't
+        // have in this repo. So instead we always link kernel32.lib and add the rest of the import
+        // libraries below by using an empty extern block. This works because extern blocks are not
+        // connected to the library given in the #[link] attribute.
+        #[link(name = "kernel32")]
+        extern $abi {
+            $(#[link_name=$link_name])?
+            pub fn $($function)*;
+        }
+    )
+}
+
+#[link(name = "advapi32")]
+#[link(name = "ntdll")]
+#[link(name = "userenv")]
+#[link(name = "ws2_32")]
+extern "C" {}
diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs
index 690b60d1dec..10aeeac07ea 100644
--- a/library/std/src/sys/pal/windows/stdio.rs
+++ b/library/std/src/sys/pal/windows/stdio.rs
@@ -232,13 +232,7 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
     debug_assert!(data.len() < u32::MAX as usize);
     let mut written = 0;
     cvt(unsafe {
-        c::WriteConsoleW(
-            handle,
-            data.as_ptr() as c::LPCVOID,
-            data.len() as u32,
-            &mut written,
-            ptr::null_mut(),
-        )
+        c::WriteConsoleW(handle, data.as_ptr(), data.len() as u32, &mut written, ptr::null_mut())
     })?;
     Ok(written as usize)
 }
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 9c24742cff1..c095127da14 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -54,7 +54,6 @@ dependencies = [
  "junction",
  "libc",
  "object",
- "once_cell",
  "opener",
  "pretty_assertions",
  "semver",
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 32dd3efa7a6..df7b5b88193 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -49,7 +49,6 @@ home = "0.5"
 ignore = "0.4"
 libc = "0.2"
 object = { version = "0.32", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
-once_cell = "1.19"
 opener = "0.5"
 semver = "1.0"
 serde = "1.0"
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 009e62469b4..46e845f77ae 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -317,9 +317,7 @@ fn format_rusage_data(child: Child) -> Option<String> {
 
     use windows::{
         Win32::Foundation::HANDLE,
-        Win32::System::ProcessStatus::{
-            K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX,
-        },
+        Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
         Win32::System::Threading::GetProcessTimes,
         Win32::System::Time::FileTimeToSystemTime,
     };
@@ -331,6 +329,7 @@ fn format_rusage_data(child: Child) -> Option<String> {
     let mut kernel_filetime = Default::default();
     let mut kernel_time = Default::default();
     let mut memory_counters = PROCESS_MEMORY_COUNTERS::default();
+    let memory_counters_size = std::mem::size_of_val(&memory_counters);
 
     unsafe {
         GetProcessTimes(
@@ -347,15 +346,9 @@ fn format_rusage_data(child: Child) -> Option<String> {
 
     // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
     // with the given handle and none of that process's children.
-    unsafe {
-        K32GetProcessMemoryInfo(
-            handle,
-            &mut memory_counters,
-            std::mem::size_of::<PROCESS_MEMORY_COUNTERS_EX>() as u32,
-        )
-    }
-    .ok()
-    .ok()?;
+    unsafe { K32GetProcessMemoryInfo(handle, &mut memory_counters, memory_counters_size as u32) }
+        .ok()
+        .ok()?;
 
     // Guide on interpreting these numbers:
     // https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index 479af4af666..a4be6bc56c5 100644
--- a/src/bootstrap/src/core/build_steps/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -85,7 +85,7 @@ macro_rules! clean_crate_tree {
 
                 // NOTE: doesn't use `run_cargo` because we don't want to save a stamp file,
                 // and doesn't use `stream_cargo` to avoid passing `--message-format` which `clean` doesn't accept.
-                builder.run(cargo);
+                cargo.run(builder);
             }
         }
     )+ }
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index a6172589dbb..11a7a404535 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -27,9 +27,9 @@ use crate::core::builder::crate_description;
 use crate::core::builder::Cargo;
 use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath};
 use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
-use crate::utils::exec::BootstrapCommand;
+use crate::utils::exec::command;
 use crate::utils::helpers::{
-    exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date,
+    exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
 };
 use crate::LLVM_TOOLS;
 use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
@@ -161,9 +161,10 @@ impl Step for Std {
             // This check is specific to testing std itself; see `test::Std` for more details.
             && !self.force_recompile
         {
+            let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
             cp_rustc_component_to_ci_sysroot(
                 builder,
-                compiler,
+                &sysroot,
                 builder.config.ci_rust_std_contents(),
             );
             return;
@@ -772,20 +773,19 @@ impl Step for StartupObjects {
             let src_file = &src_dir.join(file.to_string() + ".rs");
             let dst_file = &dst_dir.join(file.to_string() + ".o");
             if !up_to_date(src_file, dst_file) {
-                let mut cmd = BootstrapCommand::new(&builder.initial_rustc);
+                let mut cmd = command(&builder.initial_rustc);
                 cmd.env("RUSTC_BOOTSTRAP", "1");
                 if !builder.local_rebuild {
                     // a local_rebuild compiler already has stage1 features
                     cmd.arg("--cfg").arg("bootstrap");
                 }
-                builder.run(
-                    cmd.arg("--target")
-                        .arg(target.rustc_target_arg())
-                        .arg("--emit=obj")
-                        .arg("-o")
-                        .arg(dst_file)
-                        .arg(src_file),
-                );
+                cmd.arg("--target")
+                    .arg(target.rustc_target_arg())
+                    .arg("--emit=obj")
+                    .arg("-o")
+                    .arg(dst_file)
+                    .arg(src_file)
+                    .run(builder);
             }
 
             let target = sysroot_dir.join((*file).to_string() + ".o");
@@ -797,12 +797,7 @@ impl Step for StartupObjects {
     }
 }
 
-fn cp_rustc_component_to_ci_sysroot(
-    builder: &Builder<'_>,
-    compiler: Compiler,
-    contents: Vec<String>,
-) {
-    let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
+fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, contents: Vec<String>) {
     let ci_rustc_dir = builder.config.ci_rustc_dir();
 
     for file in contents {
@@ -881,13 +876,7 @@ impl Step for Rustc {
         // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler,
         // so its artifacts can't be reused.
         if builder.download_rustc() && compiler.stage != 0 {
-            // Copy the existing artifacts instead of rebuilding them.
-            // NOTE: this path is only taken for tools linking to rustc-dev (including ui-fulldeps tests).
-            cp_rustc_component_to_ci_sysroot(
-                builder,
-                compiler,
-                builder.config.ci_rustc_dev_contents(),
-            );
+            builder.ensure(Sysroot { compiler, force_recompile: false });
             return compiler.stage;
         }
 
@@ -1498,10 +1487,10 @@ pub fn compiler_file(
     if builder.config.dry_run() {
         return PathBuf::new();
     }
-    let mut cmd = Command::new(compiler);
+    let mut cmd = command(compiler);
     cmd.args(builder.cflags(target, GitRepo::Rustc, c));
     cmd.arg(format!("-print-file-name={file}"));
-    let out = output(&mut cmd);
+    let out = cmd.capture_stdout().run(builder).stdout();
     PathBuf::from(out.trim())
 }
 
@@ -1634,31 +1623,44 @@ impl Step for Sysroot {
         let sysroot_lib_rustlib_src_rust = sysroot_lib_rustlib_src.join("rust");
         if let Err(e) = symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_src_rust) {
             eprintln!(
-                "WARNING: creating symbolic link `{}` to `{}` failed with {}",
+                "ERROR: creating symbolic link `{}` to `{}` failed with {}",
                 sysroot_lib_rustlib_src_rust.display(),
                 builder.src.display(),
                 e,
             );
             if builder.config.rust_remap_debuginfo {
                 eprintln!(
-                    "WARNING: some `tests/ui` tests will fail when lacking `{}`",
+                    "ERROR: some `tests/ui` tests will fail when lacking `{}`",
                     sysroot_lib_rustlib_src_rust.display(),
                 );
             }
+            build_helper::exit!(1);
         }
-        // Same for the rustc-src component.
-        let sysroot_lib_rustlib_rustcsrc = sysroot.join("lib/rustlib/rustc-src");
-        t!(fs::create_dir_all(&sysroot_lib_rustlib_rustcsrc));
-        let sysroot_lib_rustlib_rustcsrc_rust = sysroot_lib_rustlib_rustcsrc.join("rust");
-        if let Err(e) =
-            symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_rustcsrc_rust)
-        {
-            eprintln!(
-                "WARNING: creating symbolic link `{}` to `{}` failed with {}",
-                sysroot_lib_rustlib_rustcsrc_rust.display(),
-                builder.src.display(),
-                e,
+
+        // Unlike rust-src component, we have to handle rustc-src a bit differently.
+        // When using CI rustc, we copy rustc-src component from its sysroot,
+        // otherwise we handle it in a similar way what we do for rust-src above.
+        if builder.download_rustc() {
+            cp_rustc_component_to_ci_sysroot(
+                builder,
+                &sysroot,
+                builder.config.ci_rustc_dev_contents(),
             );
+        } else {
+            let sysroot_lib_rustlib_rustcsrc = sysroot.join("lib/rustlib/rustc-src");
+            t!(fs::create_dir_all(&sysroot_lib_rustlib_rustcsrc));
+            let sysroot_lib_rustlib_rustcsrc_rust = sysroot_lib_rustlib_rustcsrc.join("rust");
+            if let Err(e) =
+                symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_rustcsrc_rust)
+            {
+                eprintln!(
+                    "ERROR: creating symbolic link `{}` to `{}` failed with {}",
+                    sysroot_lib_rustlib_rustcsrc_rust.display(),
+                    builder.src.display(),
+                    e,
+                );
+                build_helper::exit!(1);
+            }
         }
 
         sysroot
@@ -1833,7 +1835,8 @@ impl Step for Assemble {
             let llvm::LlvmResult { llvm_config, .. } =
                 builder.ensure(llvm::Llvm { target: target_compiler.host });
             if !builder.config.dry_run() && builder.config.llvm_tools_enabled {
-                let llvm_bin_dir = output(Command::new(llvm_config).arg("--bindir"));
+                let llvm_bin_dir =
+                    command(llvm_config).capture_stdout().arg("--bindir").run(builder).stdout();
                 let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
 
                 // Since we've already built the LLVM tools, install them to the sysroot.
@@ -2077,7 +2080,7 @@ pub fn stream_cargo(
     tail_args: Vec<String>,
     cb: &mut dyn FnMut(CargoMessage<'_>),
 ) -> bool {
-    let mut cargo = BootstrapCommand::from(cargo).command;
+    let mut cargo = cargo.into_cmd().command;
     // Instruct Cargo to give us json messages on stdout, critically leaving
     // stderr as piped so we can get those pretty colors.
     let mut message_format = if builder.config.json_output {
@@ -2158,8 +2161,7 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path)
     }
 
     let previous_mtime = FileTime::from_last_modification_time(&path.metadata().unwrap());
-    // NOTE: `output` will propagate any errors here.
-    output(Command::new("strip").arg("--strip-debug").arg(path));
+    command("strip").capture().arg("--strip-debug").arg(path).run(builder);
 
     // After running `strip`, we have to set the file modification time to what it was before,
     // otherwise we risk Cargo invalidating its fingerprint and rebuilding the world next time
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 08795efe5bb..7bc5405e92f 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -14,7 +14,6 @@ use std::ffi::OsStr;
 use std::fs;
 use std::io::Write;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 
 use object::read::archive::ArchiveFile;
 use object::BinaryFormat;
@@ -26,9 +25,9 @@ use crate::core::build_steps::tool::{self, Tool};
 use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::channel::{self, Info};
-use crate::utils::exec::BootstrapCommand;
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::{
-    exe, is_dylib, move_file, output, t, target_supports_cranelift_backend, timeit,
+    exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit,
 };
 use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
 use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
@@ -181,9 +180,9 @@ fn make_win_dist(
     }
 
     //Ask gcc where it keeps its stuff
-    let mut cmd = Command::new(builder.cc(target));
+    let mut cmd = command(builder.cc(target));
     cmd.arg("-print-search-dirs");
-    let gcc_out = output(&mut cmd);
+    let gcc_out = cmd.capture_stdout().run(builder).stdout();
 
     let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
     let mut lib_path = Vec::new();
@@ -1024,7 +1023,7 @@ impl Step for PlainSourceTarball {
             }
 
             // Vendor all Cargo dependencies
-            let mut cmd = Command::new(&builder.initial_cargo);
+            let mut cmd = command(&builder.initial_cargo);
             cmd.arg("vendor")
                 .arg("--versioned-dirs")
                 .arg("--sync")
@@ -1062,7 +1061,7 @@ impl Step for PlainSourceTarball {
             }
 
             let config = if !builder.config.dry_run() {
-                t!(String::from_utf8(t!(cmd.output()).stdout))
+                cmd.capture().run(builder).stdout()
             } else {
                 String::new()
             };
@@ -1600,14 +1599,14 @@ impl Step for Extended {
             let _ = fs::remove_dir_all(&pkg);
 
             let pkgbuild = |component: &str| {
-                let mut cmd = BootstrapCommand::new("pkgbuild");
+                let mut cmd = command("pkgbuild");
                 cmd.arg("--identifier")
                     .arg(format!("org.rust-lang.{}", component))
                     .arg("--scripts")
                     .arg(pkg.join(component))
                     .arg("--nopayload")
                     .arg(pkg.join(component).with_extension("pkg"));
-                builder.run(cmd);
+                cmd.run(builder);
             };
 
             let prepare = |name: &str| {
@@ -1637,7 +1636,7 @@ impl Step for Extended {
             builder.create_dir(&pkg.join("res"));
             builder.create(&pkg.join("res/LICENSE.txt"), &license);
             builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
-            let mut cmd = BootstrapCommand::new("productbuild");
+            let mut cmd = command("productbuild");
             cmd.arg("--distribution")
                 .arg(xform(&etc.join("pkg/Distribution.xml")))
                 .arg("--resources")
@@ -1650,7 +1649,7 @@ impl Step for Extended {
                 .arg("--package-path")
                 .arg(&pkg);
             let _time = timeit(builder);
-            builder.run(cmd);
+            cmd.run(builder);
         }
 
         if target.is_windows() {
@@ -1704,168 +1703,159 @@ impl Step for Extended {
             let light = wix.join("bin/light.exe");
 
             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
-            builder.run(
-                BootstrapCommand::new(&heat)
+            command(&heat)
+                .current_dir(&exe)
+                .arg("dir")
+                .arg("rustc")
+                .args(heat_flags)
+                .arg("-cg")
+                .arg("RustcGroup")
+                .arg("-dr")
+                .arg("Rustc")
+                .arg("-var")
+                .arg("var.RustcDir")
+                .arg("-out")
+                .arg(exe.join("RustcGroup.wxs"))
+                .run(builder);
+            if built_tools.contains("rust-docs") {
+                command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
-                    .arg("rustc")
+                    .arg("rust-docs")
                     .args(heat_flags)
                     .arg("-cg")
-                    .arg("RustcGroup")
+                    .arg("DocsGroup")
                     .arg("-dr")
-                    .arg("Rustc")
+                    .arg("Docs")
                     .arg("-var")
-                    .arg("var.RustcDir")
+                    .arg("var.DocsDir")
                     .arg("-out")
-                    .arg(exe.join("RustcGroup.wxs")),
-            );
-            if built_tools.contains("rust-docs") {
-                builder.run(
-                    BootstrapCommand::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("rust-docs")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("DocsGroup")
-                        .arg("-dr")
-                        .arg("Docs")
-                        .arg("-var")
-                        .arg("var.DocsDir")
-                        .arg("-out")
-                        .arg(exe.join("DocsGroup.wxs"))
-                        .arg("-t")
-                        .arg(etc.join("msi/squash-components.xsl")),
-                );
+                    .arg(exe.join("DocsGroup.wxs"))
+                    .arg("-t")
+                    .arg(etc.join("msi/squash-components.xsl"))
+                    .run(builder);
             }
-            builder.run(
-                BootstrapCommand::new(&heat)
+            command(&heat)
+                .current_dir(&exe)
+                .arg("dir")
+                .arg("cargo")
+                .args(heat_flags)
+                .arg("-cg")
+                .arg("CargoGroup")
+                .arg("-dr")
+                .arg("Cargo")
+                .arg("-var")
+                .arg("var.CargoDir")
+                .arg("-out")
+                .arg(exe.join("CargoGroup.wxs"))
+                .arg("-t")
+                .arg(etc.join("msi/remove-duplicates.xsl"))
+                .run(builder);
+            command(&heat)
+                .current_dir(&exe)
+                .arg("dir")
+                .arg("rust-std")
+                .args(heat_flags)
+                .arg("-cg")
+                .arg("StdGroup")
+                .arg("-dr")
+                .arg("Std")
+                .arg("-var")
+                .arg("var.StdDir")
+                .arg("-out")
+                .arg(exe.join("StdGroup.wxs"))
+                .run(builder);
+            if built_tools.contains("rust-analyzer") {
+                command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
-                    .arg("cargo")
+                    .arg("rust-analyzer")
                     .args(heat_flags)
                     .arg("-cg")
-                    .arg("CargoGroup")
+                    .arg("RustAnalyzerGroup")
                     .arg("-dr")
-                    .arg("Cargo")
+                    .arg("RustAnalyzer")
                     .arg("-var")
-                    .arg("var.CargoDir")
+                    .arg("var.RustAnalyzerDir")
                     .arg("-out")
-                    .arg(exe.join("CargoGroup.wxs"))
+                    .arg(exe.join("RustAnalyzerGroup.wxs"))
                     .arg("-t")
-                    .arg(etc.join("msi/remove-duplicates.xsl")),
-            );
-            builder.run(
-                BootstrapCommand::new(&heat)
+                    .arg(etc.join("msi/remove-duplicates.xsl"))
+                    .run(builder);
+            }
+            if built_tools.contains("clippy") {
+                command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
-                    .arg("rust-std")
+                    .arg("clippy")
                     .args(heat_flags)
                     .arg("-cg")
-                    .arg("StdGroup")
+                    .arg("ClippyGroup")
                     .arg("-dr")
-                    .arg("Std")
+                    .arg("Clippy")
                     .arg("-var")
-                    .arg("var.StdDir")
+                    .arg("var.ClippyDir")
                     .arg("-out")
-                    .arg(exe.join("StdGroup.wxs")),
-            );
-            if built_tools.contains("rust-analyzer") {
-                builder.run(
-                    BootstrapCommand::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("rust-analyzer")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("RustAnalyzerGroup")
-                        .arg("-dr")
-                        .arg("RustAnalyzer")
-                        .arg("-var")
-                        .arg("var.RustAnalyzerDir")
-                        .arg("-out")
-                        .arg(exe.join("RustAnalyzerGroup.wxs"))
-                        .arg("-t")
-                        .arg(etc.join("msi/remove-duplicates.xsl")),
-                );
-            }
-            if built_tools.contains("clippy") {
-                builder.run(
-                    BootstrapCommand::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("clippy")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("ClippyGroup")
-                        .arg("-dr")
-                        .arg("Clippy")
-                        .arg("-var")
-                        .arg("var.ClippyDir")
-                        .arg("-out")
-                        .arg(exe.join("ClippyGroup.wxs"))
-                        .arg("-t")
-                        .arg(etc.join("msi/remove-duplicates.xsl")),
-                );
+                    .arg(exe.join("ClippyGroup.wxs"))
+                    .arg("-t")
+                    .arg(etc.join("msi/remove-duplicates.xsl"))
+                    .run(builder);
             }
             if built_tools.contains("miri") {
-                builder.run(
-                    BootstrapCommand::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("miri")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("MiriGroup")
-                        .arg("-dr")
-                        .arg("Miri")
-                        .arg("-var")
-                        .arg("var.MiriDir")
-                        .arg("-out")
-                        .arg(exe.join("MiriGroup.wxs"))
-                        .arg("-t")
-                        .arg(etc.join("msi/remove-duplicates.xsl")),
-                );
-            }
-            builder.run(
-                BootstrapCommand::new(&heat)
+                command(&heat)
                     .current_dir(&exe)
                     .arg("dir")
-                    .arg("rust-analysis")
+                    .arg("miri")
                     .args(heat_flags)
                     .arg("-cg")
-                    .arg("AnalysisGroup")
+                    .arg("MiriGroup")
                     .arg("-dr")
-                    .arg("Analysis")
+                    .arg("Miri")
                     .arg("-var")
-                    .arg("var.AnalysisDir")
+                    .arg("var.MiriDir")
                     .arg("-out")
-                    .arg(exe.join("AnalysisGroup.wxs"))
+                    .arg(exe.join("MiriGroup.wxs"))
                     .arg("-t")
-                    .arg(etc.join("msi/remove-duplicates.xsl")),
-            );
+                    .arg(etc.join("msi/remove-duplicates.xsl"))
+                    .run(builder);
+            }
+            command(&heat)
+                .current_dir(&exe)
+                .arg("dir")
+                .arg("rust-analysis")
+                .args(heat_flags)
+                .arg("-cg")
+                .arg("AnalysisGroup")
+                .arg("-dr")
+                .arg("Analysis")
+                .arg("-var")
+                .arg("var.AnalysisDir")
+                .arg("-out")
+                .arg(exe.join("AnalysisGroup.wxs"))
+                .arg("-t")
+                .arg(etc.join("msi/remove-duplicates.xsl"))
+                .run(builder);
             if target.ends_with("windows-gnu") {
-                builder.run(
-                    BootstrapCommand::new(&heat)
-                        .current_dir(&exe)
-                        .arg("dir")
-                        .arg("rust-mingw")
-                        .args(heat_flags)
-                        .arg("-cg")
-                        .arg("GccGroup")
-                        .arg("-dr")
-                        .arg("Gcc")
-                        .arg("-var")
-                        .arg("var.GccDir")
-                        .arg("-out")
-                        .arg(exe.join("GccGroup.wxs")),
-                );
+                command(&heat)
+                    .current_dir(&exe)
+                    .arg("dir")
+                    .arg("rust-mingw")
+                    .args(heat_flags)
+                    .arg("-cg")
+                    .arg("GccGroup")
+                    .arg("-dr")
+                    .arg("Gcc")
+                    .arg("-var")
+                    .arg("var.GccDir")
+                    .arg("-out")
+                    .arg(exe.join("GccGroup.wxs"))
+                    .run(builder);
             }
 
             let candle = |input: &Path| {
                 let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
                 let arch = if target.contains("x86_64") { "x64" } else { "x86" };
-                let mut cmd = BootstrapCommand::new(&candle);
+                let mut cmd = command(&candle);
                 cmd.current_dir(&exe)
                     .arg("-nologo")
                     .arg("-dRustcDir=rustc")
@@ -1894,7 +1884,7 @@ impl Step for Extended {
                 if target.ends_with("windows-gnu") {
                     cmd.arg("-dGccDir=rust-mingw");
                 }
-                builder.run(cmd);
+                cmd.run(builder);
             };
             candle(&xform(&etc.join("msi/rust.wxs")));
             candle(&etc.join("msi/ui.wxs"));
@@ -1926,7 +1916,7 @@ impl Step for Extended {
 
             builder.info(&format!("building `msi` installer with {light:?}"));
             let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
-            let mut cmd = BootstrapCommand::new(&light);
+            let mut cmd = command(&light);
             cmd.arg("-nologo")
                 .arg("-ext")
                 .arg("WixUIExtension")
@@ -1963,7 +1953,7 @@ impl Step for Extended {
             cmd.arg("-sice:ICE57");
 
             let _time = timeit(builder);
-            builder.run(cmd);
+            cmd.run(builder);
 
             if !builder.config.dry_run() {
                 t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
@@ -2079,10 +2069,14 @@ fn maybe_install_llvm(
     } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) =
         llvm::prebuilt_llvm_config(builder, target)
     {
-        let mut cmd = Command::new(llvm_config);
+        let mut cmd = command(llvm_config);
         cmd.arg("--libfiles");
         builder.verbose(|| println!("running {cmd:?}"));
-        let files = if builder.config.dry_run() { "".into() } else { output(&mut cmd) };
+        let files = if builder.config.dry_run() {
+            "".into()
+        } else {
+            cmd.capture_stdout().run(builder).stdout()
+        };
         let build_llvm_out = &builder.llvm_out(builder.config.build);
         let target_llvm_out = &builder.llvm_out(target);
         for file in files.trim_end().split(' ') {
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 4a5af25b3b2..4b35d6c5d4c 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -154,7 +154,7 @@ impl<P: Step> Step for RustbookSrc<P> {
             builder.info(&format!("Rustbook ({target}) - {name}"));
             let _ = fs::remove_dir_all(&out);
 
-            builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out));
+            rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder);
 
             for lang in &self.languages {
                 let out = out.join(lang);
@@ -162,10 +162,15 @@ impl<P: Step> Step for RustbookSrc<P> {
                 builder.info(&format!("Rustbook ({target}) - {name} - {lang}"));
                 let _ = fs::remove_dir_all(&out);
 
-                let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
-                builder.run(
-                    rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).arg("-l").arg(lang),
-                );
+                builder
+                    .tool_cmd(Tool::Rustbook)
+                    .arg("build")
+                    .arg(&src)
+                    .arg("-d")
+                    .arg(&out)
+                    .arg("-l")
+                    .arg(lang)
+                    .run(builder);
             }
         }
 
@@ -301,7 +306,7 @@ fn invoke_rustdoc(
         cmd.arg("-Z").arg("unstable-options").arg("--disable-minification");
     }
 
-    builder.run(cmd);
+    cmd.run(builder);
 }
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -395,7 +400,7 @@ impl Step for Standalone {
             } else {
                 cmd.arg("--markdown-css").arg("rust.css");
             }
-            builder.run(cmd);
+            cmd.run(builder);
         }
 
         // We open doc/index.html as the default if invoked as `x.py doc --open`
@@ -494,7 +499,7 @@ impl Step for Releases {
                 cmd.arg("--disable-minification");
             }
 
-            builder.run(cmd);
+            cmd.run(builder);
         }
 
         // We open doc/RELEASES.html as the default if invoked as `x.py doc --open RELEASES.md`
@@ -738,7 +743,7 @@ fn doc_std(
         format!("library{} in {} format", crate_description(requested_crates), format.as_str());
     let _guard = builder.msg_doc(compiler, description, target);
 
-    builder.run(cargo);
+    cargo.into_cmd().run(builder);
     builder.cp_link_r(&out_dir, out);
 }
 
@@ -863,7 +868,7 @@ impl Step for Rustc {
         let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc");
         symlink_dir_force(&builder.config, &out, &proc_macro_out_dir);
 
-        builder.run(cargo);
+        cargo.into_cmd().run(builder);
 
         if !builder.config.dry_run() {
             // Sanity check on linked compiler crates
@@ -996,7 +1001,7 @@ macro_rules! tool_doc {
                 symlink_dir_force(&builder.config, &out, &proc_macro_out_dir);
 
                 let _guard = builder.msg_doc(compiler, stringify!($tool).to_lowercase(), target);
-                builder.run(cargo);
+                cargo.into_cmd().run(builder);
 
                 if !builder.config.dry_run() {
                     // Sanity check on linked doc directories
@@ -1075,12 +1080,7 @@ impl Step for ErrorIndex {
         builder.info(&format!("Documenting error index ({})", self.target));
         let out = builder.doc_out(self.target);
         t!(fs::create_dir_all(&out));
-        let mut index = tool::ErrorIndex::command(builder);
-        index.arg("html");
-        index.arg(out);
-        index.arg(&builder.version);
-
-        builder.run(index);
+        tool::ErrorIndex::command(builder).arg("html").arg(out).arg(&builder.version).run(builder);
     }
 }
 
@@ -1116,7 +1116,7 @@ impl Step for UnstableBookGen {
         cmd.arg(builder.src.join("src"));
         cmd.arg(out);
 
-        builder.run(cmd);
+        cmd.run(builder);
     }
 }
 
@@ -1211,7 +1211,7 @@ impl Step for RustcBook {
             self.compiler.host,
             self.target,
         );
-        builder.run(cmd);
+        cmd.run(builder);
         drop(doc_generator_guard);
 
         // Run rustbook/mdbook to generate the HTML pages.
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index f5e34672686..d3ac2bae1e8 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -1,13 +1,14 @@
 //! Runs rustfmt on the repository.
 
 use crate::core::builder::Builder;
-use crate::utils::helpers::{self, output, program_out_of_date, t};
+use crate::utils::exec::command;
+use crate::utils::helpers::{self, program_out_of_date, t};
 use build_helper::ci::CiEnv;
 use build_helper::git::get_git_modified_files;
 use ignore::WalkBuilder;
 use std::collections::VecDeque;
 use std::path::{Path, PathBuf};
-use std::process::{Command, Stdio};
+use std::process::Command;
 use std::sync::mpsc::SyncSender;
 use std::sync::Mutex;
 
@@ -53,19 +54,17 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
 fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, PathBuf)> {
     let stamp_file = build.out.join("rustfmt.stamp");
 
-    let mut cmd = Command::new(match build.initial_rustfmt() {
+    let mut cmd = command(match build.initial_rustfmt() {
         Some(p) => p,
         None => return None,
     });
     cmd.arg("--version");
-    let output = match cmd.output() {
-        Ok(status) => status,
-        Err(_) => return None,
-    };
-    if !output.status.success() {
+
+    let output = cmd.capture().allow_failure().run(build);
+    if output.is_failure() {
         return None;
     }
-    Some((String::from_utf8(output.stdout).unwrap(), stamp_file))
+    Some((output.stdout(), stamp_file))
 }
 
 /// Return whether the format cache can be reused.
@@ -160,36 +159,27 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
             override_builder.add(&format!("!{ignore}")).expect(&ignore);
         }
     }
-    let git_available = match helpers::git(None)
-        .arg("--version")
-        .stdout(Stdio::null())
-        .stderr(Stdio::null())
-        .status()
-    {
-        Ok(status) => status.success(),
-        Err(_) => false,
-    };
+    let git_available =
+        helpers::git(None).capture().allow_failure().arg("--version").run(build).is_success();
 
     let mut adjective = None;
     if git_available {
-        let in_working_tree = match helpers::git(Some(&build.src))
+        let in_working_tree = helpers::git(Some(&build.src))
+            .capture()
+            .allow_failure()
             .arg("rev-parse")
             .arg("--is-inside-work-tree")
-            .stdout(Stdio::null())
-            .stderr(Stdio::null())
-            .status()
-        {
-            Ok(status) => status.success(),
-            Err(_) => false,
-        };
+            .run(build)
+            .is_success();
         if in_working_tree {
-            let untracked_paths_output = output(
-                helpers::git(Some(&build.src))
-                    .arg("status")
-                    .arg("--porcelain")
-                    .arg("-z")
-                    .arg("--untracked-files=normal"),
-            );
+            let untracked_paths_output = helpers::git(Some(&build.src))
+                .capture_stdout()
+                .arg("status")
+                .arg("--porcelain")
+                .arg("-z")
+                .arg("--untracked-files=normal")
+                .run(build)
+                .stdout();
             let untracked_paths: Vec<_> = untracked_paths_output
                 .split_terminator('\0')
                 .filter_map(
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index 7ee1aca2abc..d3e9d6d7875 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -10,7 +10,7 @@ use std::path::{Component, Path, PathBuf};
 use crate::core::build_steps::dist;
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::core::config::{Config, TargetSelection};
-use crate::utils::exec::BootstrapCommand;
+use crate::utils::exec::command;
 use crate::utils::helpers::t;
 use crate::utils::tarball::GeneratedTarball;
 use crate::{Compiler, Kind};
@@ -102,7 +102,7 @@ fn install_sh(
     let empty_dir = builder.out.join("tmp/empty_dir");
     t!(fs::create_dir_all(&empty_dir));
 
-    let mut cmd = BootstrapCommand::new(SHELL);
+    let mut cmd = command(SHELL);
     cmd.current_dir(&empty_dir)
         .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh")))
         .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix)))
@@ -113,7 +113,7 @@ fn install_sh(
         .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir)))
         .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir)))
         .arg("--disable-ldconfig");
-    builder.run(cmd);
+    cmd.run(builder);
     t!(fs::remove_dir_all(&empty_dir));
 }
 
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 8e6795b11bd..872823506f8 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -14,7 +14,6 @@ use std::ffi::{OsStr, OsString};
 use std::fs::{self, File};
 use std::io;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 use std::sync::OnceLock;
 
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
@@ -25,6 +24,7 @@ use crate::utils::helpers::{
 };
 use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind};
 
+use crate::utils::exec::command;
 use build_helper::ci::CiEnv;
 use build_helper::git::get_git_merge_base;
 
@@ -172,7 +172,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
             // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
             config.src.join("src/version"),
         ]);
-        output(&mut rev_list).trim().to_owned()
+        output(&mut rev_list.command).trim().to_owned()
     } else if let Some(info) = channel::read_commit_info_file(&config.src) {
         info.sha.trim().to_owned()
     } else {
@@ -253,7 +253,8 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool {
         // We assume we have access to git, so it's okay to unconditionally pass
         // `true` here.
         let llvm_sha = detect_llvm_sha(config, true);
-        let head_sha = output(helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD"));
+        let head_sha =
+            output(&mut helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").command);
         let head_sha = head_sha.trim();
         llvm_sha == head_sha
     }
@@ -477,7 +478,8 @@ impl Step for Llvm {
             let LlvmResult { llvm_config, .. } =
                 builder.ensure(Llvm { target: builder.config.build });
             if !builder.config.dry_run() {
-                let llvm_bindir = output(Command::new(&llvm_config).arg("--bindir"));
+                let llvm_bindir =
+                    command(&llvm_config).capture_stdout().arg("--bindir").run(builder).stdout();
                 let host_bin = Path::new(llvm_bindir.trim());
                 cfg.define(
                     "LLVM_TABLEGEN",
@@ -527,8 +529,8 @@ impl Step for Llvm {
 
         // Helper to find the name of LLVM's shared library on darwin and linux.
         let find_llvm_lib_name = |extension| {
-            let mut cmd = Command::new(&res.llvm_config);
-            let version = output(cmd.arg("--version"));
+            let version =
+                command(&res.llvm_config).capture_stdout().arg("--version").run(builder).stdout();
             let major = version.split('.').next().unwrap();
 
             match &llvm_version_suffix {
@@ -584,8 +586,7 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
         return;
     }
 
-    let mut cmd = Command::new(llvm_config);
-    let version = output(cmd.arg("--version"));
+    let version = command(llvm_config).capture_stdout().arg("--version").run(builder).stdout();
     let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
     if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
         if major >= 17 {
@@ -752,7 +753,7 @@ fn configure_cmake(
     }
 
     if builder.config.llvm_clang_cl.is_some() {
-        cflags.push(&format!(" --target={target}"));
+        cflags.push(format!(" --target={target}"));
     }
     cfg.define("CMAKE_C_FLAGS", cflags);
     let mut cxxflags: OsString = builder
@@ -771,7 +772,7 @@ fn configure_cmake(
         cxxflags.push(s);
     }
     if builder.config.llvm_clang_cl.is_some() {
-        cxxflags.push(&format!(" --target={target}"));
+        cxxflags.push(format!(" --target={target}"));
     }
     cfg.define("CMAKE_CXX_FLAGS", cxxflags);
     if let Some(ar) = builder.ar(target) {
@@ -912,7 +913,7 @@ impl Step for Lld {
                 // Find clang's runtime library directory and push that as a search path to the
                 // cmake linker flags.
                 let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
-                ldflags.push_all(&format!("/libpath:{}", clang_rt_dir.display()));
+                ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
             }
         }
 
diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs
index f41b5fe10f1..5b83080a326 100644
--- a/src/bootstrap/src/core/build_steps/perf.rs
+++ b/src/bootstrap/src/core/build_steps/perf.rs
@@ -31,5 +31,5 @@ Consider setting `rust.debuginfo-level = 1` in `config.toml`."#);
         .env("PERF_COLLECTOR", collector)
         .env("PERF_RESULT_DIR", profile_results_dir)
         .args(args);
-    builder.run(&mut cmd);
+    cmd.run(builder);
 }
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 22d5efa5d95..3a2d3f67522 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -4,7 +4,6 @@
 //! If it can be reached from `./x.py run` it can go here.
 
 use std::path::PathBuf;
-use std::process::Command;
 
 use crate::core::build_steps::dist::distdir;
 use crate::core::build_steps::test;
@@ -12,7 +11,7 @@ use crate::core::build_steps::tool::{self, SourceType, Tool};
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::core::config::flags::get_completion;
 use crate::core::config::TargetSelection;
-use crate::utils::helpers::output;
+use crate::utils::exec::command;
 use crate::Mode;
 
 #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
@@ -41,7 +40,7 @@ impl Step for BuildManifest {
             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
         });
 
-        let today = output(Command::new("date").arg("+%Y-%m-%d"));
+        let today = command("date").capture_stdout().arg("+%Y-%m-%d").run(builder).stdout();
 
         cmd.arg(sign);
         cmd.arg(distdir(builder));
@@ -50,7 +49,7 @@ impl Step for BuildManifest {
         cmd.arg(&builder.config.channel);
 
         builder.create_dir(&distdir(builder));
-        builder.run(cmd);
+        cmd.run(builder);
     }
 }
 
@@ -72,7 +71,7 @@ impl Step for BumpStage0 {
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let mut cmd = builder.tool_cmd(Tool::BumpStage0);
         cmd.args(builder.config.args());
-        builder.run(cmd);
+        cmd.run(builder);
     }
 }
 
@@ -94,7 +93,7 @@ impl Step for ReplaceVersionPlaceholder {
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder);
         cmd.arg(&builder.src);
-        builder.run(cmd);
+        cmd.run(builder);
     }
 }
 
@@ -158,7 +157,7 @@ impl Step for Miri {
         // after another --, so this must be at the end.
         miri.args(builder.config.args());
 
-        builder.run(miri);
+        miri.into_cmd().run(builder);
     }
 }
 
@@ -188,7 +187,7 @@ impl Step for CollectLicenseMetadata {
         let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
         cmd.env("REUSE_EXE", reuse);
         cmd.env("DEST", &dest);
-        builder.run(cmd);
+        cmd.run(builder);
 
         dest
     }
@@ -218,7 +217,7 @@ impl Step for GenerateCopyright {
         let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
         cmd.env("LICENSE_METADATA", &license_metadata);
         cmd.env("DEST", &dest);
-        builder.run(cmd);
+        cmd.run(builder);
 
         dest
     }
@@ -242,7 +241,7 @@ impl Step for GenerateWindowsSys {
     fn run(self, builder: &Builder<'_>) {
         let mut cmd = builder.tool_cmd(Tool::GenerateWindowsSys);
         cmd.arg(&builder.src);
-        builder.run(cmd);
+        cmd.run(builder);
     }
 }
 
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 947c74f32c9..e6a09e8cb8e 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -484,6 +484,7 @@ impl Step for Hook {
 fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
     let git = helpers::git(Some(&config.src))
         .args(["rev-parse", "--git-common-dir"])
+        .command
         .output()
         .map(|output| {
             assert!(output.status.success(), "failed to run `git`");
diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs
index 7c5e0d4e13e..2d4409d27c6 100644
--- a/src/bootstrap/src/core/build_steps/suggest.rs
+++ b/src/bootstrap/src/core/build_steps/suggest.rs
@@ -14,23 +14,12 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
     let git_config = builder.config.git_config();
     let suggestions = builder
         .tool_cmd(Tool::SuggestTests)
+        .capture_stdout()
         .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository)
         .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
-        .command
-        .output()
-        .expect("failed to run `suggest-tests` tool");
+        .run(builder)
+        .stdout();
 
-    if !suggestions.status.success() {
-        println!("failed to run `suggest-tests` tool ({})", suggestions.status);
-        println!(
-            "`suggest_tests` stdout:\n{}`suggest_tests` stderr:\n{}",
-            String::from_utf8(suggestions.stdout).unwrap(),
-            String::from_utf8(suggestions.stderr).unwrap()
-        );
-        panic!("failed to run `suggest-tests`");
-    }
-
-    let suggestions = String::from_utf8(suggestions.stdout).unwrap();
     let suggestions = suggestions
         .lines()
         .map(|line| {
diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
index 281a9b093b9..021680302cd 100644
--- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs
+++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
@@ -9,8 +9,8 @@
 
 use crate::core::builder::{Builder, ShouldRun, Step};
 use crate::core::config::TargetSelection;
+use crate::utils::exec::command;
 use crate::Compiler;
-use std::process::{Command, Stdio};
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub(crate) struct MirOptPanicAbortSyntheticTarget {
@@ -56,7 +56,7 @@ fn create_synthetic_target(
         return TargetSelection::create_synthetic(&name, path.to_str().unwrap());
     }
 
-    let mut cmd = Command::new(builder.rustc(compiler));
+    let mut cmd = command(builder.rustc(compiler));
     cmd.arg("--target").arg(base.rustc_target_arg());
     cmd.args(["-Zunstable-options", "--print", "target-spec-json"]);
 
@@ -64,14 +64,8 @@ fn create_synthetic_target(
     // we cannot use nightly features. So `RUSTC_BOOTSTRAP` is needed here.
     cmd.env("RUSTC_BOOTSTRAP", "1");
 
-    cmd.stdout(Stdio::piped());
-
-    let output = cmd.spawn().unwrap().wait_with_output().unwrap();
-    if !output.status.success() {
-        panic!("failed to gather the target spec for {base}");
-    }
-
-    let mut spec: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
+    let output = cmd.capture().run(builder).stdout();
+    let mut spec: serde_json::Value = serde_json::from_slice(output.as_bytes()).unwrap();
     let spec_map = spec.as_object_mut().unwrap();
 
     // The `is-builtin` attribute of a spec needs to be removed, otherwise rustc will complain.
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 1460a229019..7f4c4bd53df 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -26,11 +26,10 @@ use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::flags::get_completion;
 use crate::core::config::flags::Subcommand;
 use crate::core::config::TargetSelection;
-use crate::utils::exec::{BootstrapCommand, OutputMode};
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::{
     self, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var,
-    linker_args, linker_flags, output, t, target_supports_cranelift_backend, up_to_date,
-    LldThreads,
+    linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, LldThreads,
 };
 use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
 use crate::{envify, CLang, DocTests, GitRepo, Mode};
@@ -150,16 +149,13 @@ You can skip linkcheck with --skip src/tools/linkchecker"
         builder.default_doc(&[]);
 
         // Build the linkchecker before calling `msg`, since GHA doesn't support nested groups.
-        let mut linkchecker = builder.tool_cmd(Tool::Linkchecker);
+        let linkchecker = builder.tool_cmd(Tool::Linkchecker);
 
         // Run the linkchecker.
         let _guard =
             builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host);
         let _time = helpers::timeit(builder);
-        builder.run(
-            BootstrapCommand::from(linkchecker.arg(builder.out.join(host.triple).join("doc")))
-                .delay_failure(),
-        );
+        linkchecker.delay_failure().arg(builder.out.join(host.triple).join("doc")).run(builder);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -216,12 +212,11 @@ impl Step for HtmlCheck {
             builder,
         ));
 
-        builder.run(
-            BootstrapCommand::from(
-                builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)),
-            )
-            .delay_failure(),
-        );
+        builder
+            .tool_cmd(Tool::HtmlChecker)
+            .delay_failure()
+            .arg(builder.doc_out(self.target))
+            .run(builder);
     }
 }
 
@@ -260,14 +255,13 @@ impl Step for Cargotest {
 
         let _time = helpers::timeit(builder);
         let mut cmd = builder.tool_cmd(Tool::CargoTest);
-        let cmd = cmd
-            .arg(&cargo)
+        cmd.arg(&cargo)
             .arg(&out_dir)
             .args(builder.config.test_args())
             .env("RUSTC", builder.rustc(compiler))
             .env("RUSTDOC", builder.rustdoc(compiler));
-        add_rustdoc_cargo_linker_args(cmd, builder, compiler.host, LldThreads::No);
-        builder.run(BootstrapCommand::from(cmd).delay_failure());
+        add_rustdoc_cargo_linker_args(&mut cmd, builder, compiler.host, LldThreads::No);
+        cmd.delay_failure().run(builder);
     }
 }
 
@@ -468,7 +462,7 @@ impl Miri {
         let mut cargo = BootstrapCommand::from(cargo);
         let _guard =
             builder.msg(Kind::Build, compiler.stage, "miri sysroot", compiler.host, target);
-        builder.run(&mut cargo);
+        cargo.run(builder);
 
         // # Determine where Miri put its sysroot.
         // To this end, we run `cargo miri setup --print-sysroot` and capture the output.
@@ -477,19 +471,12 @@ impl Miri {
         // We re-use the `cargo` from above.
         cargo.arg("--print-sysroot");
 
-        // FIXME: Is there a way in which we can re-use the usual `run` helpers?
         if builder.config.dry_run() {
             String::new()
         } else {
             builder.verbose(|| println!("running: {cargo:?}"));
-            let out = cargo
-                .command
-                .output()
-                .expect("We already ran `cargo miri setup` before and that worked");
-            assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code");
+            let stdout = cargo.capture_stdout().run(builder).stdout();
             // Output is "<sysroot>\n".
-            let stdout = String::from_utf8(out.stdout)
-                .expect("`cargo miri setup` stdout is not valid UTF-8");
             let sysroot = stdout.trim_end();
             builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
             sysroot.to_owned()
@@ -576,7 +563,7 @@ impl Step for Miri {
         {
             let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "miri", host, target);
             let _time = helpers::timeit(builder);
-            builder.run(&mut cargo);
+            cargo.run(builder);
         }
 
         // Run it again for mir-opt-level 4 to catch some miscompilations.
@@ -598,7 +585,7 @@ impl Step for Miri {
                     target,
                 );
                 let _time = helpers::timeit(builder);
-                builder.run(cargo);
+                cargo.run(builder);
             }
         }
     }
@@ -663,11 +650,11 @@ impl Step for CargoMiri {
 
         // Finally, pass test-args and run everything.
         cargo.arg("--").args(builder.config.test_args());
-        let cargo = BootstrapCommand::from(cargo);
+        let mut cargo = BootstrapCommand::from(cargo);
         {
             let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "cargo-miri", host, target);
             let _time = helpers::timeit(builder);
-            builder.run(cargo);
+            cargo.run(builder);
         }
     }
 }
@@ -763,12 +750,12 @@ impl Step for Clippy {
         cargo.env("HOST_LIBS", host_libs);
 
         cargo.add_rustc_lib_path(builder);
-        let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
+        let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
 
         let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host);
 
         // Clippy reports errors if it blessed the outputs
-        if builder.run(BootstrapCommand::from(&mut cargo).allow_failure()).is_success() {
+        if cargo.allow_failure().run(builder).is_success() {
             // The tests succeeded; nothing to do.
             return;
         }
@@ -821,7 +808,7 @@ impl Step for RustdocTheme {
             .env("RUSTC_BOOTSTRAP", "1");
         cmd.args(linker_args(builder, self.compiler.host, LldThreads::No));
 
-        builder.run(BootstrapCommand::from(&mut cmd).delay_failure());
+        cmd.delay_failure().run(builder);
     }
 }
 
@@ -847,7 +834,7 @@ impl Step for RustdocJSStd {
     fn run(self, builder: &Builder<'_>) {
         let nodejs =
             builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");
-        let mut command = BootstrapCommand::new(nodejs);
+        let mut command = command(nodejs);
         command
             .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
             .arg("--crate-name")
@@ -881,7 +868,7 @@ impl Step for RustdocJSStd {
             builder.config.build,
             self.target,
         );
-        builder.run(command);
+        command.run(builder);
     }
 }
 
@@ -918,25 +905,26 @@ impl Step for RustdocJSNotStd {
     }
 }
 
-fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> {
-    let mut command = Command::new(npm);
+fn get_browser_ui_test_version_inner(
+    builder: &Builder<'_>,
+    npm: &Path,
+    global: bool,
+) -> Option<String> {
+    let mut command = command(npm).capture();
     command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
     if global {
         command.arg("--global");
     }
-    let lines = command
-        .output()
-        .map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
-        .unwrap_or_default();
+    let lines = command.allow_failure().run(builder).stdout();
     lines
         .lines()
         .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
         .map(|v| v.to_owned())
 }
 
-fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
-    get_browser_ui_test_version_inner(npm, false)
-        .or_else(|| get_browser_ui_test_version_inner(npm, true))
+fn get_browser_ui_test_version(builder: &Builder<'_>, npm: &Path) -> Option<String> {
+    get_browser_ui_test_version_inner(builder, npm, false)
+        .or_else(|| get_browser_ui_test_version_inner(builder, npm, true))
 }
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -960,7 +948,7 @@ impl Step for RustdocGUI {
                     .config
                     .npm
                     .as_ref()
-                    .map(|p| get_browser_ui_test_version(p).is_some())
+                    .map(|p| get_browser_ui_test_version(builder, p).is_some())
                     .unwrap_or(false)
         }))
     }
@@ -1099,7 +1087,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to
         }
 
         builder.info("tidy check");
-        builder.run(BootstrapCommand::from(&mut cmd).delay_failure());
+        cmd.delay_failure().run(builder);
 
         builder.info("x.py completions check");
         let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"]
@@ -1306,7 +1294,7 @@ impl Step for RunMakeSupport {
             &[],
         );
 
-        builder.run(cargo);
+        cargo.into_cmd().run(builder);
 
         let lib_name = "librun_make_support.rlib";
         let lib = builder.tools_dir(self.compiler).join(lib_name);
@@ -1818,26 +1806,22 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         }
 
         let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb"));
-        let lldb_version = Command::new(&lldb_exe)
+        let lldb_version = command(&lldb_exe)
+            .capture()
+            .allow_failure()
             .arg("--version")
-            .output()
-            .map(|output| {
-                (String::from_utf8_lossy(&output.stdout).to_string(), output.status.success())
-            })
-            .ok()
-            .and_then(|(output, success)| if success { Some(output) } else { None });
+            .run(builder)
+            .stdout_if_ok()
+            .and_then(|v| if v.trim().is_empty() { None } else { Some(v) });
         if let Some(ref vers) = lldb_version {
-            let run = |cmd: &mut Command| {
-                cmd.output().map(|output| {
-                    String::from_utf8_lossy(&output.stdout)
-                        .lines()
-                        .next()
-                        .unwrap_or_else(|| panic!("{:?} failed {:?}", cmd, output))
-                        .to_string()
-                })
-            };
             cmd.arg("--lldb-version").arg(vers);
-            let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
+            let lldb_python_dir = command(&lldb_exe)
+                .allow_failure()
+                .capture_stdout()
+                .arg("-P")
+                .run(builder)
+                .stdout_if_ok()
+                .map(|p| p.lines().next().expect("lldb Python dir not found").to_string());
             if let Some(ref dir) = lldb_python_dir {
                 cmd.arg("--lldb-python-dir").arg(dir);
             }
@@ -1893,8 +1877,11 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             let llvm::LlvmResult { llvm_config, .. } =
                 builder.ensure(llvm::Llvm { target: builder.config.build });
             if !builder.config.dry_run() {
-                let llvm_version = output(Command::new(&llvm_config).arg("--version"));
-                let llvm_components = output(Command::new(&llvm_config).arg("--components"));
+                let llvm_version =
+                    builder.run(command(&llvm_config).capture_stdout().arg("--version")).stdout();
+                let llvm_components = builder
+                    .run(command(&llvm_config).capture_stdout().arg("--components"))
+                    .stdout();
                 // Remove trailing newline from llvm-config output.
                 cmd.arg("--llvm-version")
                     .arg(llvm_version.trim())
@@ -1913,7 +1900,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             // separate compilations. We can add LLVM's library path to the
             // platform-specific environment variable as a workaround.
             if !builder.config.dry_run() && suite.ends_with("fulldeps") {
-                let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
+                let llvm_libdir =
+                    builder.run(command(&llvm_config).capture_stdout().arg("--libdir")).stdout();
                 add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd);
             }
 
@@ -2187,9 +2175,11 @@ impl BookTest {
             compiler.host,
         );
         let _time = helpers::timeit(builder);
-        let cmd = BootstrapCommand::from(&mut rustbook_cmd).delay_failure();
-        let toolstate =
-            if builder.run(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail };
+        let toolstate = if rustbook_cmd.delay_failure().run(builder).is_success() {
+            ToolState::TestPass
+        } else {
+            ToolState::TestFail
+        };
         builder.save_toolstate(self.name, toolstate);
     }
 
@@ -2318,7 +2308,7 @@ impl Step for ErrorIndex {
         let guard =
             builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host);
         let _time = helpers::timeit(builder);
-        builder.run(BootstrapCommand::from(&mut tool).output_mode(OutputMode::OnlyOnFailure));
+        tool.capture().run(builder);
         drop(guard);
         // The tests themselves need to link to std, so make sure it is
         // available.
@@ -2349,9 +2339,9 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
 
     cmd = cmd.delay_failure();
     if !builder.config.verbose_tests {
-        cmd = cmd.quiet();
+        cmd = cmd.capture();
     }
-    builder.run(cmd).is_success()
+    cmd.run(builder).is_success()
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -2375,10 +2365,13 @@ impl Step for RustcGuide {
         builder.update_submodule(&relative_path);
 
         let src = builder.src.join(relative_path);
-        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
-        let cmd = BootstrapCommand::from(rustbook_cmd.arg("linkcheck").arg(&src)).delay_failure();
-        let toolstate =
-            if builder.run(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail };
+        let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook).delay_failure();
+        rustbook_cmd.arg("linkcheck").arg(&src);
+        let toolstate = if rustbook_cmd.run(builder).is_success() {
+            ToolState::TestPass
+        } else {
+            ToolState::TestFail
+        };
         builder.save_toolstate("rustc-dev-guide", toolstate);
     }
 }
@@ -2878,19 +2871,19 @@ impl Step for RemoteCopyLibs {
 
         // Spawn the emulator and wait for it to come online
         let tool = builder.tool_exe(Tool::RemoteTestClient);
-        let mut cmd = BootstrapCommand::new(&tool);
+        let mut cmd = command(&tool);
         cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.tempdir());
         if let Some(rootfs) = builder.qemu_rootfs(target) {
             cmd.arg(rootfs);
         }
-        builder.run(cmd);
+        cmd.run(builder);
 
         // Push all our dylibs to the emulator
         for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
             let f = t!(f);
             let name = f.file_name().into_string().unwrap();
             if helpers::is_dylib(&name) {
-                builder.run(BootstrapCommand::new(&tool).arg("push").arg(f.path()));
+                builder.run(command(&tool).arg("push").arg(f.path()));
             }
         }
     }
@@ -2921,22 +2914,20 @@ impl Step for Distcheck {
         builder.ensure(dist::PlainSourceTarball);
         builder.ensure(dist::Src);
 
-        let mut cmd = BootstrapCommand::new("tar");
+        let mut cmd = command("tar");
         cmd.arg("-xf")
             .arg(builder.ensure(dist::PlainSourceTarball).tarball())
             .arg("--strip-components=1")
             .current_dir(&dir);
-        builder.run(cmd);
+        cmd.run(builder);
         builder.run(
-            BootstrapCommand::new("./configure")
+            command("./configure")
                 .args(&builder.config.configure_args)
                 .arg("--enable-vendor")
                 .current_dir(&dir),
         );
         builder.run(
-            BootstrapCommand::new(helpers::make(&builder.config.build.triple))
-                .arg("check")
-                .current_dir(&dir),
+            command(helpers::make(&builder.config.build.triple)).arg("check").current_dir(&dir),
         );
 
         // Now make sure that rust-src has all of libstd's dependencies
@@ -2945,16 +2936,16 @@ impl Step for Distcheck {
         let _ = fs::remove_dir_all(&dir);
         t!(fs::create_dir_all(&dir));
 
-        let mut cmd = BootstrapCommand::new("tar");
+        let mut cmd = command("tar");
         cmd.arg("-xf")
             .arg(builder.ensure(dist::Src).tarball())
             .arg("--strip-components=1")
             .current_dir(&dir);
-        builder.run(cmd);
+        cmd.run(builder);
 
         let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml");
         builder.run(
-            BootstrapCommand::new(&builder.initial_cargo)
+            command(&builder.initial_cargo)
                 // Will read the libstd Cargo.toml
                 // which uses the unstable `public-dependency` feature.
                 .env("RUSTC_BOOTSTRAP", "1")
@@ -2983,7 +2974,7 @@ impl Step for Bootstrap {
         // Some tests require cargo submodule to be present.
         builder.build.update_submodule(Path::new("src/tools/cargo"));
 
-        let mut check_bootstrap = BootstrapCommand::new(builder.python());
+        let mut check_bootstrap = command(builder.python());
         check_bootstrap
             .args(["-m", "unittest", "bootstrap_test.py"])
             .env("BUILD_DIR", &builder.out)
@@ -2991,9 +2982,9 @@ impl Step for Bootstrap {
             .current_dir(builder.src.join("src/bootstrap/"));
         // NOTE: we intentionally don't pass test_args here because the args for unittest and cargo test are mutually incompatible.
         // Use `python -m unittest` manually if you want to pass arguments.
-        builder.run(check_bootstrap.delay_failure());
+        check_bootstrap.delay_failure().run(builder);
 
-        let mut cmd = BootstrapCommand::new(&builder.initial_cargo);
+        let mut cmd = command(&builder.initial_cargo);
         cmd.arg("test")
             .args(["--features", "bootstrap-self-test"])
             .current_dir(builder.src.join("src/bootstrap"))
@@ -3068,7 +3059,7 @@ impl Step for TierCheck {
             self.compiler.host,
             self.compiler.host,
         );
-        builder.run(BootstrapCommand::from(cargo).delay_failure());
+        BootstrapCommand::from(cargo).delay_failure().run(builder);
     }
 }
 
@@ -3144,7 +3135,7 @@ impl Step for RustInstaller {
             return;
         }
 
-        let mut cmd = BootstrapCommand::new(builder.src.join("src/tools/rust-installer/test.sh"));
+        let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh"));
         let tmpdir = testdir(builder, compiler.host).join("rust-installer");
         let _ = std::fs::remove_dir_all(&tmpdir);
         let _ = std::fs::create_dir_all(&tmpdir);
@@ -3153,7 +3144,7 @@ impl Step for RustInstaller {
         cmd.env("CARGO", &builder.initial_cargo);
         cmd.env("RUSTC", &builder.initial_rustc);
         cmd.env("TMP_DIR", &tmpdir);
-        builder.run(cmd.delay_failure());
+        cmd.delay_failure().run(builder);
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -3347,7 +3338,7 @@ impl Step for CodegenCranelift {
             .arg("testsuite.extended_sysroot");
         cargo.args(builder.config.test_args());
 
-        builder.run(cargo);
+        cargo.into_cmd().run(builder);
     }
 }
 
@@ -3472,6 +3463,6 @@ impl Step for CodegenGCC {
             .arg("--std-tests");
         cargo.args(builder.config.test_args());
 
-        builder.run(cargo);
+        cargo.into_cmd().run(builder);
     }
 }
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index b3464043912..ad92a01bce7 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1,7 +1,6 @@
 use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 
 use crate::core::build_steps::compile;
 use crate::core::build_steps::toolstate::ToolState;
@@ -9,8 +8,7 @@ use crate::core::builder;
 use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::channel::GitInfo;
-use crate::utils::exec::BootstrapCommand;
-use crate::utils::helpers::output;
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::{add_dylib_path, exe, t};
 use crate::Compiler;
 use crate::Mode;
@@ -246,6 +244,7 @@ macro_rules! bootstrap_tool {
         ;
     )+) => {
         #[derive(PartialEq, Eq, Clone)]
+        #[allow(dead_code)]
         pub enum Tool {
             $(
                 $name,
@@ -439,7 +438,7 @@ impl ErrorIndex {
         // for rustc_private and libLLVM.so, and `sysroot_lib` for libstd, etc.
         let host = builder.config.build;
         let compiler = builder.compiler_for(builder.top_stage, host, host);
-        let mut cmd = BootstrapCommand::new(builder.ensure(ErrorIndex { compiler }));
+        let mut cmd = command(builder.ensure(ErrorIndex { compiler }));
         let mut dylib_paths = builder.rustc_lib_paths(compiler);
         dylib_paths.push(PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host)));
         add_dylib_path(dylib_paths, &mut cmd);
@@ -603,7 +602,7 @@ impl Step for Rustdoc {
             &self.compiler.host,
             &target,
         );
-        builder.run(cargo);
+        cargo.into_cmd().run(builder);
 
         // Cargo adds a number of paths to the dylib search path on windows, which results in
         // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
@@ -858,7 +857,7 @@ impl Step for LlvmBitcodeLinker {
             &self.extra_features,
         );
 
-        builder.run(cargo);
+        cargo.into_cmd().run(builder);
 
         let tool_out = builder
             .cargo_out(self.compiler, Mode::ToolRustc, self.target)
@@ -913,20 +912,20 @@ impl Step for LibcxxVersionTool {
             }
 
             let compiler = builder.cxx(self.target).unwrap();
-            let mut cmd = BootstrapCommand::new(compiler);
+            let mut cmd = command(compiler);
 
             cmd.arg("-o")
                 .arg(&executable)
                 .arg(builder.src.join("src/tools/libcxx-version/main.cpp"));
 
-            builder.run(cmd);
+            cmd.run(builder);
 
             if !executable.exists() {
                 panic!("Something went wrong. {} is not present", executable.display());
             }
         }
 
-        let version_output = output(&mut Command::new(executable));
+        let version_output = command(executable).capture_stdout().run(builder).stdout();
 
         let version_str = version_output.split_once("version:").unwrap().1;
         let version = version_str.trim().parse::<usize>().unwrap();
@@ -1050,7 +1049,7 @@ impl<'a> Builder<'a> {
     /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for
     /// `host`.
     pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand {
-        let mut cmd = BootstrapCommand::new(self.tool_exe(tool));
+        let mut cmd = command(self.tool_exe(tool));
         let compiler = self.compiler(0, self.config.build);
         let host = &compiler.host;
         // Prepares the `cmd` provided to be able to run the `compiler` provided.
diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs
index 9e6d03349b5..e3e7931a5a2 100644
--- a/src/bootstrap/src/core/build_steps/toolstate.rs
+++ b/src/bootstrap/src/core/build_steps/toolstate.rs
@@ -101,8 +101,13 @@ fn print_error(tool: &str, submodule: &str) {
 
 fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
     // Changed files
-    let output =
-        helpers::git(None).arg("diff").arg("--name-status").arg("HEAD").arg("HEAD^").output();
+    let output = helpers::git(None)
+        .arg("diff")
+        .arg("--name-status")
+        .arg("HEAD")
+        .arg("HEAD^")
+        .command
+        .output();
     let output = match output {
         Ok(o) => o,
         Err(e) => {
@@ -324,6 +329,7 @@ fn checkout_toolstate_repo() {
         .arg("--depth=1")
         .arg(toolstate_repo())
         .arg(TOOLSTATE_DIR)
+        .command
         .status();
     let success = match status {
         Ok(s) => s.success(),
@@ -337,7 +343,8 @@ fn checkout_toolstate_repo() {
 /// Sets up config and authentication for modifying the toolstate repo.
 fn prepare_toolstate_config(token: &str) {
     fn git_config(key: &str, value: &str) {
-        let status = helpers::git(None).arg("config").arg("--global").arg(key).arg(value).status();
+        let status =
+            helpers::git(None).arg("config").arg("--global").arg(key).arg(value).command.status();
         let success = match status {
             Ok(s) => s.success(),
             Err(_) => false,
@@ -406,6 +413,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
             .arg("-a")
             .arg("-m")
             .arg(&message)
+            .command
             .status());
         if !status.success() {
             success = true;
@@ -416,6 +424,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
             .arg("push")
             .arg("origin")
             .arg("master")
+            .command
             .status());
         // If we successfully push, exit.
         if status.success() {
@@ -428,12 +437,14 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
             .arg("fetch")
             .arg("origin")
             .arg("master")
+            .command
             .status());
         assert!(status.success());
         let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
             .arg("reset")
             .arg("--hard")
             .arg("origin/master")
+            .command
             .status());
         assert!(status.success());
     }
@@ -449,7 +460,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
 /// `publish_toolstate.py` script if the PR passes all tests and is merged to
 /// master.
 fn publish_test_results(current_toolstate: &ToolstateData) {
-    let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").output());
+    let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").command.output());
     let commit = t!(String::from_utf8(commit.stdout));
 
     let toolstate_serialized = t!(serde_json::to_string(&current_toolstate));
diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs
index 0b999a24a1f..62342ee4792 100644
--- a/src/bootstrap/src/core/build_steps/vendor.rs
+++ b/src/bootstrap/src/core/build_steps/vendor.rs
@@ -1,5 +1,5 @@
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::utils::exec::BootstrapCommand;
+use crate::utils::exec::command;
 use std::path::{Path, PathBuf};
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -27,7 +27,7 @@ impl Step for Vendor {
     }
 
     fn run(self, builder: &Builder<'_>) -> Self::Output {
-        let mut cmd = BootstrapCommand::new(&builder.initial_cargo);
+        let mut cmd = command(&builder.initial_cargo);
         cmd.arg("vendor");
 
         if self.versioned_dirs {
@@ -59,6 +59,6 @@ impl Step for Vendor {
 
         cmd.current_dir(self.root_dir);
 
-        builder.run(cmd);
+        cmd.run(builder);
     }
 }
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 58d6e7a58e3..65cc1fa7478 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -8,7 +8,7 @@ use std::fs;
 use std::hash::Hash;
 use std::ops::Deref;
 use std::path::{Path, PathBuf};
-use std::process::Command;
+use std::sync::LazyLock;
 use std::time::{Duration, Instant};
 
 use crate::core::build_steps::tool::{self, SourceType};
@@ -20,16 +20,14 @@ use crate::core::config::{DryRun, SplitDebuginfo, TargetSelection};
 use crate::prepare_behaviour_dump_dir;
 use crate::utils::cache::Cache;
 use crate::utils::helpers::{self, add_dylib_path, add_link_lib_path, exe, linker_args};
-use crate::utils::helpers::{check_cfg_arg, libdir, linker_flags, output, t, LldThreads};
+use crate::utils::helpers::{check_cfg_arg, libdir, linker_flags, t, LldThreads};
 use crate::EXTRA_CHECK_CFGS;
 use crate::{Build, CLang, Crate, DocTests, GitRepo, Mode};
 
-use crate::utils::exec::BootstrapCommand;
+use crate::utils::exec::{command, BootstrapCommand};
 pub use crate::Compiler;
 
 use clap::ValueEnum;
-// FIXME: replace with std::lazy after it gets stabilized and reaches beta
-use once_cell::sync::Lazy;
 
 #[cfg(test)]
 mod tests;
@@ -499,7 +497,7 @@ impl StepDescription {
 
 enum ReallyDefault<'a> {
     Bool(bool),
-    Lazy(Lazy<bool, Box<dyn Fn() -> bool + 'a>>),
+    Lazy(LazyLock<bool, Box<dyn Fn() -> bool + 'a>>),
 }
 
 pub struct ShouldRun<'a> {
@@ -530,7 +528,7 @@ impl<'a> ShouldRun<'a> {
     }
 
     pub fn lazy_default_condition(mut self, lazy_cond: Box<dyn Fn() -> bool + 'a>) -> Self {
-        self.is_really_default = ReallyDefault::Lazy(Lazy::new(lazy_cond));
+        self.is_really_default = ReallyDefault::Lazy(LazyLock::new(lazy_cond));
         self
     }
 
@@ -1255,7 +1253,7 @@ impl<'a> Builder<'a> {
         if run_compiler.stage == 0 {
             // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy.
             let cargo_clippy = self.build.config.download_clippy();
-            let mut cmd = BootstrapCommand::new(cargo_clippy);
+            let mut cmd = command(cargo_clippy);
             cmd.env("CARGO", &self.initial_cargo);
             return cmd;
         }
@@ -1274,7 +1272,7 @@ impl<'a> Builder<'a> {
         let mut dylib_path = helpers::dylib_path();
         dylib_path.insert(0, self.sysroot(run_compiler).join("lib"));
 
-        let mut cmd = BootstrapCommand::new(cargo_clippy);
+        let mut cmd = command(cargo_clippy);
         cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
         cmd.env("CARGO", &self.initial_cargo);
         cmd
@@ -1296,7 +1294,7 @@ impl<'a> Builder<'a> {
             extra_features: Vec::new(),
         });
         // Invoke cargo-miri, make sure it can find miri and cargo.
-        let mut cmd = BootstrapCommand::new(cargo_miri);
+        let mut cmd = command(cargo_miri);
         cmd.env("MIRI", &miri);
         cmd.env("CARGO", &self.initial_cargo);
         // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`,
@@ -1312,7 +1310,7 @@ impl<'a> Builder<'a> {
     }
 
     pub fn rustdoc_cmd(&self, compiler: Compiler) -> BootstrapCommand {
-        let mut cmd = BootstrapCommand::new(self.bootstrap_out.join("rustdoc"));
+        let mut cmd = command(self.bootstrap_out.join("rustdoc"));
         cmd.env("RUSTC_STAGE", compiler.stage.to_string())
             .env("RUSTC_SYSROOT", self.sysroot(compiler))
             // Note that this is *not* the sysroot_libdir because rustdoc must be linked
@@ -1366,7 +1364,7 @@ impl<'a> Builder<'a> {
             cargo = self.cargo_miri_cmd(compiler);
             cargo.arg("miri").arg(subcmd);
         } else {
-            cargo = BootstrapCommand::new(&self.initial_cargo);
+            cargo = command(&self.initial_cargo);
             cargo.arg(cmd);
         }
 
@@ -1919,7 +1917,8 @@ impl<'a> Builder<'a> {
         // platform-specific environment variable as a workaround.
         if mode == Mode::ToolRustc || mode == Mode::Codegen {
             if let Some(llvm_config) = self.llvm_config(target) {
-                let llvm_libdir = output(Command::new(llvm_config).arg("--libdir"));
+                let llvm_libdir =
+                    command(llvm_config).capture_stdout().arg("--libdir").run(self).stdout();
                 add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo);
             }
         }
@@ -2398,6 +2397,10 @@ impl Cargo {
         cargo
     }
 
+    pub fn into_cmd(self) -> BootstrapCommand {
+        self.into()
+    }
+
     /// Same as `Cargo::new` except this one doesn't configure the linker with `Cargo::configure_linker`
     pub fn new_for_mir_opt_tests(
         builder: &Builder<'_>,
@@ -2522,7 +2525,7 @@ impl Cargo {
 
         if let Some(target_linker) = builder.linker(target) {
             let target = crate::envify(&target.triple);
-            self.command.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
+            self.command.env(format!("CARGO_TARGET_{target}_LINKER"), target_linker);
         }
         // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
         // `linker_args` here.
@@ -2622,9 +2625,3 @@ impl From<Cargo> for BootstrapCommand {
         cargo.command
     }
 }
-
-impl From<Cargo> for Command {
-    fn from(cargo: Cargo) -> Command {
-        BootstrapCommand::from(cargo).command
-    }
-}
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 948f97e746f..10ac6c93e9a 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1259,6 +1259,7 @@ impl Config {
         cmd.arg("rev-parse").arg("--show-cdup");
         // Discard stderr because we expect this to fail when building from a tarball.
         let output = cmd
+            .command
             .stderr(std::process::Stdio::null())
             .output()
             .ok()
@@ -2141,7 +2142,7 @@ impl Config {
 
         let mut git = helpers::git(Some(&self.src));
         git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap()));
-        output(&mut git)
+        output(&mut git.command)
     }
 
     /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
@@ -2445,8 +2446,9 @@ impl Config {
         };
 
         // Handle running from a directory other than the top level
-        let top_level =
-            output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]));
+        let top_level = output(
+            &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command,
+        );
         let top_level = top_level.trim_end();
         let compiler = format!("{top_level}/compiler/");
         let library = format!("{top_level}/library/");
@@ -2454,10 +2456,11 @@ impl Config {
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let merge_base = output(
-            helpers::git(Some(&self.src))
+            &mut helpers::git(Some(&self.src))
                 .arg("rev-list")
                 .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
-                .args(["-n1", "--first-parent", "HEAD"]),
+                .args(["-n1", "--first-parent", "HEAD"])
+                .command,
         );
         let commit = merge_base.trim_end();
         if commit.is_empty() {
@@ -2471,6 +2474,7 @@ impl Config {
         // Warn if there were changes to the compiler or standard library since the ancestor commit.
         let has_changes = !t!(helpers::git(Some(&self.src))
             .args(["diff-index", "--quiet", commit, "--", &compiler, &library])
+            .command
             .status())
         .success();
         if has_changes {
@@ -2542,17 +2546,19 @@ impl Config {
         if_unchanged: bool,
     ) -> Option<String> {
         // Handle running from a directory other than the top level
-        let top_level =
-            output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]));
+        let top_level = output(
+            &mut helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"]).command,
+        );
         let top_level = top_level.trim_end();
 
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let merge_base = output(
-            helpers::git(Some(&self.src))
+            &mut helpers::git(Some(&self.src))
                 .arg("rev-list")
                 .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email))
-                .args(["-n1", "--first-parent", "HEAD"]),
+                .args(["-n1", "--first-parent", "HEAD"])
+                .command,
         );
         let commit = merge_base.trim_end();
         if commit.is_empty() {
@@ -2571,7 +2577,7 @@ impl Config {
             git.arg(format!("{top_level}/{path}"));
         }
 
-        let has_changes = !t!(git.status()).success();
+        let has_changes = !t!(git.command.status()).success();
         if has_changes {
             if if_unchanged {
                 if self.verbose > 0 {
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index c35398e2eb7..a7f4bb0cf14 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -11,7 +11,7 @@ use std::{
 use build_helper::ci::CiEnv;
 use xz2::bufread::XzDecoder;
 
-use crate::utils::exec::BootstrapCommand;
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::utils::helpers::hex_encode;
 use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date};
 use crate::{t, Config};
@@ -212,7 +212,7 @@ impl Config {
     fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
         println!("downloading {url}");
         // Try curl. If that fails and we are on windows, fallback to PowerShell.
-        let mut curl = BootstrapCommand::new("curl");
+        let mut curl = command("curl");
         curl.args([
             "-y",
             "30",
diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs
index 220eb5ba126..b18da844014 100644
--- a/src/bootstrap/src/core/metadata.rs
+++ b/src/bootstrap/src/core/metadata.rs
@@ -1,9 +1,8 @@
 use std::path::PathBuf;
-use std::process::Command;
 
 use serde_derive::Deserialize;
 
-use crate::utils::helpers::output;
+use crate::utils::exec::command;
 use crate::{t, Build, Crate};
 
 /// For more information, see the output of
@@ -71,7 +70,7 @@ pub fn build(build: &mut Build) {
 /// particular crate (e.g., `x build sysroot` to build library/sysroot).
 fn workspace_members(build: &Build) -> Vec<Package> {
     let collect_metadata = |manifest_path| {
-        let mut cargo = Command::new(&build.initial_cargo);
+        let mut cargo = command(&build.initial_cargo);
         cargo
             // Will read the libstd Cargo.toml
             // which uses the unstable `public-dependency` feature.
@@ -82,7 +81,7 @@ fn workspace_members(build: &Build) -> Vec<Package> {
             .arg("--no-deps")
             .arg("--manifest-path")
             .arg(build.src.join(manifest_path));
-        let metadata_output = output(&mut cargo);
+        let metadata_output = cargo.capture_stdout().run_always().run(build).stdout();
         let Output { packages, .. } = t!(serde_json::from_str(&metadata_output));
         packages
     };
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 5a0be2948a1..9995da3a1e5 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -13,7 +13,6 @@ use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fs;
 use std::path::PathBuf;
-use std::process::Command;
 
 #[cfg(not(feature = "bootstrap-self-test"))]
 use crate::builder::Builder;
@@ -24,7 +23,7 @@ use std::collections::HashSet;
 
 use crate::builder::Kind;
 use crate::core::config::Target;
-use crate::utils::helpers::output;
+use crate::utils::exec::command;
 use crate::Build;
 
 pub struct Finder {
@@ -209,11 +208,12 @@ than building it.
         .or_else(|| cmd_finder.maybe_have("reuse"));
 
     #[cfg(not(feature = "bootstrap-self-test"))]
-    let stage0_supported_target_list: HashSet<String> =
-        output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"]))
-            .lines()
-            .map(|s| s.to_string())
-            .collect();
+    let stage0_supported_target_list: HashSet<String> = crate::utils::helpers::output(
+        &mut command(&build.config.initial_rustc).args(["--print", "target-list"]).command,
+    )
+    .lines()
+    .map(|s| s.to_string())
+    .collect();
 
     // We're gonna build some custom C code here and there, host triples
     // also build some C++ shims for LLVM so we need a C++ compiler.
@@ -352,7 +352,7 @@ than building it.
             // There are three builds of cmake on windows: MSVC, MinGW, and
             // Cygwin. The Cygwin build does not have generators for Visual
             // Studio, so detect that here and error.
-            let out = output(Command::new("cmake").arg("--help"));
+            let out = command("cmake").capture_stdout().arg("--help").run(build).stdout();
             if !out.contains("Visual Studio") {
                 panic!(
                     "
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 8d7e43a1bf1..f16afb29796 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -26,10 +26,10 @@ use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::str;
 use std::sync::OnceLock;
+use std::time::SystemTime;
 
 use build_helper::ci::{gha, CiEnv};
 use build_helper::exit;
-use build_helper::util::fail;
 use filetime::FileTime;
 use sha2::digest::Digest;
 use termcolor::{ColorChoice, StandardStream, WriteColor};
@@ -41,7 +41,7 @@ use crate::core::builder::Kind;
 use crate::core::config::{flags, LldMode};
 use crate::core::config::{DryRun, Target};
 use crate::core::config::{LlvmLibunwind, TargetSelection};
-use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode};
+use crate::utils::exec::{command, BehaviorOnFailure, BootstrapCommand, CommandOutput};
 use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir};
 
 mod core;
@@ -493,11 +493,12 @@ impl Build {
         let submodule_git = || helpers::git(Some(&absolute_path));
 
         // Determine commit checked out in submodule.
-        let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]));
+        let checked_out_hash = output(&mut submodule_git().args(["rev-parse", "HEAD"]).command);
         let checked_out_hash = checked_out_hash.trim_end();
         // Determine commit that the submodule *should* have.
-        let recorded =
-            output(helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path));
+        let recorded = output(
+            &mut helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path).command,
+        );
         let actual_hash = recorded
             .split_whitespace()
             .nth(2)
@@ -509,9 +510,10 @@ impl Build {
         }
 
         println!("Updating submodule {}", relative_path.display());
-        self.run(
-            helpers::git(Some(&self.src)).args(["submodule", "-q", "sync"]).arg(relative_path),
-        );
+        helpers::git(Some(&self.src))
+            .args(["submodule", "-q", "sync"])
+            .arg(relative_path)
+            .run(self);
 
         // Try passing `--progress` to start, then run git again without if that fails.
         let update = |progress: bool| {
@@ -520,6 +522,7 @@ impl Build {
             let current_branch = {
                 let output = helpers::git(Some(&self.src))
                     .args(["symbolic-ref", "--short", "HEAD"])
+                    .command
                     .stderr(Stdio::inherit())
                     .output();
                 let output = t!(output);
@@ -545,27 +548,26 @@ impl Build {
             git
         };
         // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
-        if !update(true).status().map_or(false, |status| status.success()) {
-            self.run(update(false));
+        if !update(true).command.status().map_or(false, |status| status.success()) {
+            update(false).run(self);
         }
 
         // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error).
         // diff-index reports the modifications through the exit status
-        let has_local_modifications = self
-            .run(
-                BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"]))
-                    .allow_failure(),
-            )
+        let has_local_modifications = submodule_git()
+            .allow_failure()
+            .args(["diff-index", "--quiet", "HEAD"])
+            .run(self)
             .is_failure();
         if has_local_modifications {
-            self.run(submodule_git().args(["stash", "push"]));
+            submodule_git().args(["stash", "push"]).run(self);
         }
 
-        self.run(submodule_git().args(["reset", "-q", "--hard"]));
-        self.run(submodule_git().args(["clean", "-qdfx"]));
+        submodule_git().args(["reset", "-q", "--hard"]).run(self);
+        submodule_git().args(["clean", "-qdfx"]).run(self);
 
         if has_local_modifications {
-            self.run(submodule_git().args(["stash", "pop"]));
+            submodule_git().args(["stash", "pop"]).run(self);
         }
     }
 
@@ -576,12 +578,13 @@ impl Build {
         if !self.config.submodules(self.rust_info()) {
             return;
         }
-        let output = output(
-            helpers::git(Some(&self.src))
-                .args(["config", "--file"])
-                .arg(self.config.src.join(".gitmodules"))
-                .args(["--get-regexp", "path"]),
-        );
+        let output = helpers::git(Some(&self.src))
+            .capture()
+            .args(["config", "--file"])
+            .arg(self.config.src.join(".gitmodules"))
+            .args(["--get-regexp", "path"])
+            .run(self)
+            .stdout();
         for line in output.lines() {
             // Look for `submodule.$name.path = $path`
             // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
@@ -858,14 +861,14 @@ impl Build {
         if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) {
             s.to_path_buf()
         } else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
-            let llvm_bindir = output(Command::new(s).arg("--bindir"));
+            let llvm_bindir = command(s).capture_stdout().arg("--bindir").run(self).stdout();
             let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", target));
             if filecheck.exists() {
                 filecheck
             } else {
                 // On Fedora the system LLVM installs FileCheck in the
                 // llvm subdirectory of the libdir.
-                let llvm_libdir = output(Command::new(s).arg("--libdir"));
+                let llvm_libdir = command(s).capture_stdout().arg("--libdir").run(self).stdout();
                 let lib_filecheck =
                     Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", target));
                 if lib_filecheck.exists() {
@@ -931,66 +934,78 @@ impl Build {
 
     /// Execute a command and return its output.
     /// This method should be used for all command executions in bootstrap.
-    fn run<C: Into<BootstrapCommand>>(&self, command: C) -> CommandOutput {
-        if self.config.dry_run() {
+    fn run(&self, command: &mut BootstrapCommand) -> CommandOutput {
+        if self.config.dry_run() && !command.run_always {
             return CommandOutput::default();
         }
 
-        let mut command = command.into();
-
         self.verbose(|| println!("running: {command:?}"));
 
-        let output_mode = command.output_mode.unwrap_or_else(|| match self.is_verbose() {
-            true => OutputMode::All,
-            false => OutputMode::OnlyOutput,
-        });
-        let (output, print_error): (io::Result<CommandOutput>, bool) = match output_mode {
-            mode @ (OutputMode::All | OutputMode::OnlyOutput) => (
-                command.command.status().map(|status| status.into()),
-                matches!(mode, OutputMode::All),
-            ),
-            OutputMode::OnlyOnFailure => (command.command.output().map(|o| o.into()), true),
-        };
-
-        let output = match output {
-            Ok(output) => output,
-            Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", command, e)),
-        };
-        if !output.is_success() {
-            if print_error {
-                println!(
-                    "\n\nCommand did not execute successfully.\
-                \nExpected success, got: {}",
-                    output.status(),
-                );
-
-                if !self.is_verbose() {
-                    println!("Add `-v` to see more details.\n");
+        command.command.stdout(command.stdout.stdio());
+        command.command.stderr(command.stderr.stdio());
+
+        let output = command.command.output();
+
+        use std::fmt::Write;
+
+        let mut message = String::new();
+        let output: CommandOutput = match output {
+            // Command has succeeded
+            Ok(output) if output.status.success() => output.into(),
+            // Command has started, but then it failed
+            Ok(output) => {
+                writeln!(
+                    message,
+                    "\n\nCommand {command:?} did not execute successfully.\
+            \nExpected success, got: {}",
+                    output.status,
+                )
+                .unwrap();
+
+                let output: CommandOutput = output.into();
+
+                // If the output mode is OutputMode::Capture, we can now print the output.
+                // If it is OutputMode::Print, then the output has already been printed to
+                // stdout/stderr, and we thus don't have anything captured to print anyway.
+                if command.stdout.captures() {
+                    writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap();
                 }
-
-                self.verbose(|| {
-                    println!(
-                        "\nSTDOUT ----\n{}\n\
-                    STDERR ----\n{}\n",
-                        output.stdout(),
-                        output.stderr(),
-                    )
-                });
+                if command.stderr.captures() {
+                    writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap();
+                }
+                output
             }
-
+            // The command did not even start
+            Err(e) => {
+                writeln!(
+                    message,
+                    "\n\nCommand {command:?} did not execute successfully.\
+            \nIt was not possible to execute the command: {e:?}"
+                )
+                .unwrap();
+                CommandOutput::did_not_start()
+            }
+        };
+        if !output.is_success() {
             match command.failure_behavior {
                 BehaviorOnFailure::DelayFail => {
                     if self.fail_fast {
+                        println!("{message}");
                         exit!(1);
                     }
 
                     let mut failures = self.delayed_failures.borrow_mut();
-                    failures.push(format!("{command:?}"));
+                    failures.push(message);
                 }
                 BehaviorOnFailure::Exit => {
+                    println!("{message}");
                     exit!(1);
                 }
-                BehaviorOnFailure::Ignore => {}
+                BehaviorOnFailure::Ignore => {
+                    // If failures are allowed, either the error has been printed already
+                    // (OutputMode::Print) or the user used a capture output mode and wants to
+                    // handle the error output on their own.
+                }
             }
         }
         output
@@ -1479,14 +1494,17 @@ impl Build {
             // Figure out how many merge commits happened since we branched off master.
             // That's our beta number!
             // (Note that we use a `..` range, not the `...` symmetric difference.)
-            output(
-                helpers::git(Some(&self.src)).arg("rev-list").arg("--count").arg("--merges").arg(
-                    format!(
-                        "refs/remotes/origin/{}..HEAD",
-                        self.config.stage0_metadata.config.nightly_branch
-                    ),
-                ),
-            )
+            helpers::git(Some(&self.src))
+                .capture()
+                .arg("rev-list")
+                .arg("--count")
+                .arg("--merges")
+                .arg(format!(
+                    "refs/remotes/origin/{}..HEAD",
+                    self.config.stage0_metadata.config.nightly_branch
+                ))
+                .run(self)
+                .stdout()
         });
         let n = count.trim().parse().unwrap();
         self.prerelease_version.set(Some(n));
@@ -1647,7 +1665,14 @@ impl Build {
         if src == dst {
             return;
         }
-        let _ = fs::remove_file(dst);
+        if let Err(e) = fs::remove_file(dst) {
+            if cfg!(windows) && e.kind() != io::ErrorKind::NotFound {
+                // workaround for https://github.com/rust-lang/rust/issues/127126
+                // if removing the file fails, attempt to rename it instead.
+                let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH));
+                let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos()));
+            }
+        }
         let metadata = t!(src.symlink_metadata(), format!("src = {}", src.display()));
         let mut src = src.to_path_buf();
         if metadata.file_type().is_symlink() {
@@ -1906,6 +1931,7 @@ fn envify(s: &str) -> String {
 pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String {
     let diff = helpers::git(Some(dir))
         .arg("diff")
+        .command
         .output()
         .map(|o| String::from_utf8(o.stdout).unwrap_or_default())
         .unwrap_or_default();
@@ -1915,6 +1941,7 @@ pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String {
         .arg("--porcelain")
         .arg("-z")
         .arg("--untracked-files=normal")
+        .command
         .output()
         .map(|o| String::from_utf8(o.stdout).unwrap_or_default())
         .unwrap_or_default();
diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs
index e18dcbb47be..d60b54dc703 100644
--- a/src/bootstrap/src/utils/cache.rs
+++ b/src/bootstrap/src/utils/cache.rs
@@ -9,10 +9,7 @@ use std::marker::PhantomData;
 use std::mem;
 use std::ops::Deref;
 use std::path::PathBuf;
-use std::sync::Mutex;
-
-// FIXME: replace with std::lazy after it gets stabilized and reaches beta
-use once_cell::sync::Lazy;
+use std::sync::{LazyLock, Mutex};
 
 use crate::core::builder::Step;
 
@@ -196,7 +193,7 @@ impl Interner {
     }
 }
 
-pub static INTERNER: Lazy<Interner> = Lazy::new(Interner::default);
+pub static INTERNER: LazyLock<Interner> = LazyLock::new(Interner::default);
 
 /// This is essentially a `HashMap` which allows storing any type in its input and
 /// any type in its output. It is a write-once cache; values are never evicted,
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index 540b8671333..d6fa7fc0bbe 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -23,11 +23,10 @@
 
 use std::collections::HashSet;
 use std::path::{Path, PathBuf};
-use std::process::Command;
 use std::{env, iter};
 
 use crate::core::config::TargetSelection;
-use crate::utils::helpers::output;
+use crate::utils::exec::{command, BootstrapCommand};
 use crate::{Build, CLang, GitRepo};
 
 // The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
@@ -183,14 +182,15 @@ fn default_compiler(
                 return None;
             }
 
-            let output = output(c.to_command().arg("--version"));
+            let cmd = BootstrapCommand::from(c.to_command());
+            let output = cmd.capture_stdout().arg("--version").run(build).stdout();
             let i = output.find(" 4.")?;
             match output[i + 3..].chars().next().unwrap() {
                 '0'..='6' => {}
                 _ => return None,
             }
             let alternative = format!("e{gnu_compiler}");
-            if Command::new(&alternative).output().is_ok() {
+            if command(&alternative).capture().run(build).is_success() {
                 Some(PathBuf::from(alternative))
             } else {
                 None
diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs
index ce82c52f049..2ca86bdb0ed 100644
--- a/src/bootstrap/src/utils/channel.rs
+++ b/src/bootstrap/src/utils/channel.rs
@@ -45,7 +45,7 @@ impl GitInfo {
         }
 
         // Make sure git commands work
-        match helpers::git(Some(dir)).arg("rev-parse").output() {
+        match helpers::git(Some(dir)).arg("rev-parse").command.output() {
             Ok(ref out) if out.status.success() => {}
             _ => return GitInfo::Absent,
         }
@@ -58,15 +58,17 @@ impl GitInfo {
 
         // Ok, let's scrape some info
         let ver_date = output(
-            helpers::git(Some(dir))
+            &mut helpers::git(Some(dir))
                 .arg("log")
                 .arg("-1")
                 .arg("--date=short")
-                .arg("--pretty=format:%cd"),
+                .arg("--pretty=format:%cd")
+                .command,
+        );
+        let ver_hash = output(&mut helpers::git(Some(dir)).arg("rev-parse").arg("HEAD").command);
+        let short_ver_hash = output(
+            &mut helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD").command,
         );
-        let ver_hash = output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD"));
-        let short_ver_hash =
-            output(helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD"));
         GitInfo::Present(Some(Info {
             commit_date: ver_date.trim().to_string(),
             sha: ver_hash.trim().to_string(),
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index 8bcb2301f1a..ba963f52dc2 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -1,6 +1,7 @@
+use crate::Build;
 use std::ffi::OsStr;
 use std::path::Path;
-use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output};
+use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio};
 
 /// What should be done when the command fails.
 #[derive(Debug, Copy, Clone)]
@@ -13,16 +14,30 @@ pub enum BehaviorOnFailure {
     Ignore,
 }
 
-/// How should the output of the command be handled.
+/// How should the output of a specific stream of the command (stdout/stderr) be handled
+/// (whether it should be captured or printed).
 #[derive(Debug, Copy, Clone)]
 pub enum OutputMode {
-    /// Print both the output (by inheriting stdout/stderr) and also the command itself, if it
-    /// fails.
-    All,
-    /// Print the output (by inheriting stdout/stderr).
-    OnlyOutput,
-    /// Suppress the output if the command succeeds, otherwise print the output.
-    OnlyOnFailure,
+    /// Prints the stream by inheriting it from the bootstrap process.
+    Print,
+    /// Captures the stream into memory.
+    Capture,
+}
+
+impl OutputMode {
+    pub fn captures(&self) -> bool {
+        match self {
+            OutputMode::Print => false,
+            OutputMode::Capture => true,
+        }
+    }
+
+    pub fn stdio(&self) -> Stdio {
+        match self {
+            OutputMode::Print => Stdio::inherit(),
+            OutputMode::Capture => Stdio::piped(),
+        }
+    }
 }
 
 /// Wrapper around `std::process::Command`.
@@ -31,10 +46,10 @@ pub enum OutputMode {
 /// If you want to allow failures, use [allow_failure].
 /// If you want to delay failures until the end of bootstrap, use [delay_failure].
 ///
-/// By default, the command will print its stdout/stderr to stdout/stderr of bootstrap
-/// ([OutputMode::OnlyOutput]). If bootstrap uses verbose mode, then it will also print the
-/// command itself in case of failure ([OutputMode::All]).
-/// If you want to handle the output programmatically, use `output_mode(OutputMode::OnlyOnFailure)`.
+/// By default, the command will print its stdout/stderr to stdout/stderr of bootstrap ([OutputMode::Print]).
+/// If you want to handle the output programmatically, use [BootstrapCommand::capture].
+///
+/// Bootstrap will print a debug log to stdout if the command fails and failure is not allowed.
 ///
 /// [allow_failure]: BootstrapCommand::allow_failure
 /// [delay_failure]: BootstrapCommand::delay_failure
@@ -42,7 +57,10 @@ pub enum OutputMode {
 pub struct BootstrapCommand {
     pub command: Command,
     pub failure_behavior: BehaviorOnFailure,
-    pub output_mode: Option<OutputMode>,
+    pub stdout: OutputMode,
+    pub stderr: OutputMode,
+    // Run the command even during dry run
+    pub run_always: bool,
 }
 
 impl BootstrapCommand {
@@ -91,107 +109,138 @@ impl BootstrapCommand {
         self
     }
 
+    #[must_use]
     pub fn delay_failure(self) -> Self {
         Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self }
     }
 
+    #[must_use]
     pub fn fail_fast(self) -> Self {
         Self { failure_behavior: BehaviorOnFailure::Exit, ..self }
     }
 
+    #[must_use]
     pub fn allow_failure(self) -> Self {
         Self { failure_behavior: BehaviorOnFailure::Ignore, ..self }
     }
 
-    /// Do not print the output of the command, unless it fails.
-    pub fn quiet(self) -> Self {
-        self.output_mode(OutputMode::OnlyOnFailure)
+    pub fn run_always(&mut self) -> &mut Self {
+        self.run_always = true;
+        self
     }
 
-    pub fn output_mode(self, output_mode: OutputMode) -> Self {
-        Self { output_mode: Some(output_mode), ..self }
+    /// Capture all output of the command, do not print it.
+    #[must_use]
+    pub fn capture(self) -> Self {
+        Self { stdout: OutputMode::Capture, stderr: OutputMode::Capture, ..self }
     }
-}
-
-/// This implementation is temporary, until all `Command` invocations are migrated to
-/// `BootstrapCommand`.
-impl<'a> From<&'a mut Command> for BootstrapCommand {
-    fn from(command: &'a mut Command) -> Self {
-        // This is essentially a manual `Command::clone`
-        let mut cmd = Command::new(command.get_program());
-        if let Some(dir) = command.get_current_dir() {
-            cmd.current_dir(dir);
-        }
-        cmd.args(command.get_args());
-        for (key, value) in command.get_envs() {
-            match value {
-                Some(value) => {
-                    cmd.env(key, value);
-                }
-                None => {
-                    cmd.env_remove(key);
-                }
-            }
-        }
 
-        cmd.into()
+    /// Capture stdout of the command, do not print it.
+    #[must_use]
+    pub fn capture_stdout(self) -> Self {
+        Self { stdout: OutputMode::Capture, ..self }
     }
-}
 
-/// This implementation is temporary, until all `Command` invocations are migrated to
-/// `BootstrapCommand`.
-impl<'a> From<&'a mut BootstrapCommand> for BootstrapCommand {
-    fn from(command: &'a mut BootstrapCommand) -> Self {
-        BootstrapCommand::from(&mut command.command)
+    /// Run the command, returning its output.
+    pub fn run(&mut self, builder: &Build) -> CommandOutput {
+        builder.run(self)
     }
 }
 
 impl From<Command> for BootstrapCommand {
     fn from(command: Command) -> Self {
-        Self { command, failure_behavior: BehaviorOnFailure::Exit, output_mode: None }
+        Self {
+            command,
+            failure_behavior: BehaviorOnFailure::Exit,
+            stdout: OutputMode::Print,
+            stderr: OutputMode::Print,
+            run_always: false,
+        }
     }
 }
 
+/// Represents the current status of `BootstrapCommand`.
+enum CommandStatus {
+    /// The command has started and finished with some status.
+    Finished(ExitStatus),
+    /// It was not even possible to start the command.
+    DidNotStart,
+}
+
+/// Create a new BootstrapCommand. This is a helper function to make command creation
+/// shorter than `BootstrapCommand::new`.
+#[must_use]
+pub fn command<S: AsRef<OsStr>>(program: S) -> BootstrapCommand {
+    BootstrapCommand::new(program)
+}
+
 /// Represents the output of an executed process.
 #[allow(unused)]
-pub struct CommandOutput(Output);
+pub struct CommandOutput {
+    status: CommandStatus,
+    stdout: Vec<u8>,
+    stderr: Vec<u8>,
+}
 
 impl CommandOutput {
+    #[must_use]
+    pub fn did_not_start() -> Self {
+        Self { status: CommandStatus::DidNotStart, stdout: vec![], stderr: vec![] }
+    }
+
+    #[must_use]
     pub fn is_success(&self) -> bool {
-        self.0.status.success()
+        match self.status {
+            CommandStatus::Finished(status) => status.success(),
+            CommandStatus::DidNotStart => false,
+        }
     }
 
+    #[must_use]
     pub fn is_failure(&self) -> bool {
         !self.is_success()
     }
 
-    pub fn status(&self) -> ExitStatus {
-        self.0.status
+    #[must_use]
+    pub fn status(&self) -> Option<ExitStatus> {
+        match self.status {
+            CommandStatus::Finished(status) => Some(status),
+            CommandStatus::DidNotStart => None,
+        }
     }
 
+    #[must_use]
     pub fn stdout(&self) -> String {
-        String::from_utf8(self.0.stdout.clone()).expect("Cannot parse process stdout as UTF-8")
+        String::from_utf8(self.stdout.clone()).expect("Cannot parse process stdout as UTF-8")
     }
 
+    #[must_use]
+    pub fn stdout_if_ok(&self) -> Option<String> {
+        if self.is_success() { Some(self.stdout()) } else { None }
+    }
+
+    #[must_use]
     pub fn stderr(&self) -> String {
-        String::from_utf8(self.0.stderr.clone()).expect("Cannot parse process stderr as UTF-8")
+        String::from_utf8(self.stderr.clone()).expect("Cannot parse process stderr as UTF-8")
     }
 }
 
 impl Default for CommandOutput {
     fn default() -> Self {
-        Self(Output { status: Default::default(), stdout: vec![], stderr: vec![] })
+        Self {
+            status: CommandStatus::Finished(ExitStatus::default()),
+            stdout: vec![],
+            stderr: vec![],
+        }
     }
 }
 
 impl From<Output> for CommandOutput {
     fn from(output: Output) -> Self {
-        Self(output)
-    }
-}
-
-impl From<ExitStatus> for CommandOutput {
-    fn from(status: ExitStatus) -> Self {
-        Self(Output { status, stdout: vec![], stderr: vec![] })
+        Self {
+            status: CommandStatus::Finished(output.status),
+            stdout: output.stdout,
+            stderr: output.stderr,
+        }
     }
 }
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index adf18c0ace1..5dd3ba96786 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -47,7 +47,7 @@ macro_rules! t {
         }
     };
 }
-use crate::utils::exec::BootstrapCommand;
+use crate::utils::exec::{command, BootstrapCommand};
 pub use t;
 
 pub fn exe(name: &str, target: TargetSelection) -> String {
@@ -360,7 +360,7 @@ pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf {
 /// Returns a flag that configures LLD to use only a single thread.
 /// If we use an external LLD, we need to find out which version is it to know which flag should we
 /// pass to it (LLD older than version 10 had a different flag).
-fn lld_flag_no_threads(lld_mode: LldMode, is_windows: bool) -> &'static str {
+fn lld_flag_no_threads(builder: &Builder<'_>, lld_mode: LldMode, is_windows: bool) -> &'static str {
     static LLD_NO_THREADS: OnceLock<(&'static str, &'static str)> = OnceLock::new();
 
     let new_flags = ("/threads:1", "--threads=1");
@@ -369,7 +369,9 @@ fn lld_flag_no_threads(lld_mode: LldMode, is_windows: bool) -> &'static str {
     let (windows_flag, other_flag) = LLD_NO_THREADS.get_or_init(|| {
         let newer_version = match lld_mode {
             LldMode::External => {
-                let out = output(Command::new("lld").arg("-flavor").arg("ld").arg("--version"));
+                let mut cmd = command("lld").capture_stdout();
+                cmd.arg("-flavor").arg("ld").arg("--version");
+                let out = cmd.run(builder).stdout();
                 match (out.find(char::is_numeric), out.find('.')) {
                     (Some(b), Some(e)) => out.as_str()[b..e].parse::<i32>().ok().unwrap_or(14) > 10,
                     _ => true,
@@ -431,7 +433,7 @@ pub fn linker_flags(
         if matches!(lld_threads, LldThreads::No) {
             args.push(format!(
                 "-Clink-arg=-Wl,{}",
-                lld_flag_no_threads(builder.config.lld_mode, target.is_windows())
+                lld_flag_no_threads(builder, builder.config.lld_mode, target.is_windows())
             ));
         }
     }
@@ -492,14 +494,15 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String {
     format!("--check-cfg=cfg({name}{next})")
 }
 
-/// Prepares `Command` that runs git inside the source directory if given.
+/// Prepares `BootstrapCommand` that runs git inside the source directory if given.
 ///
 /// Whenever a git invocation is needed, this function should be preferred over
-/// manually building a git `Command`. This approach allows us to manage bootstrap-specific
-/// needs/hacks from a single source, rather than applying them on next to every `Command::new("git")`,
-/// which is painful to ensure that the required change is applied on each one of them correctly.
-pub fn git(source_dir: Option<&Path>) -> Command {
-    let mut git = Command::new("git");
+/// manually building a git `BootstrapCommand`. This approach allows us to manage
+/// bootstrap-specific needs/hacks from a single source, rather than applying them on next to every
+/// git command creation, which is painful to ensure that the required change is applied
+/// on each one of them correctly.
+pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
+    let mut git = command("git");
 
     if let Some(source_dir) = source_dir {
         git.current_dir(source_dir);
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 5cc319826db..4f0104e4bba 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -9,9 +9,9 @@ use std::path::{Path, PathBuf};
 
 use crate::core::builder::Builder;
 use crate::core::{build_steps::dist::distdir, builder::Kind};
-use crate::utils::channel;
 use crate::utils::exec::BootstrapCommand;
 use crate::utils::helpers::{move_file, t};
+use crate::utils::{channel, helpers};
 
 #[derive(Copy, Clone)]
 pub(crate) enum OverlayKind {
@@ -351,7 +351,35 @@ impl<'a> Tarball<'a> {
         };
 
         cmd.args(["--compression-profile", compression_profile]);
-        self.builder.run(cmd);
+
+        // We want to use a pinned modification time for files in the archive
+        // to achieve better reproducibility. However, using the same mtime for all
+        // releases is not ideal, because it can break e.g. Cargo mtime checking
+        // (https://github.com/rust-lang/rust/issues/125578).
+        // Therefore, we set mtime to the date of the latest commit (if we're managed
+        // by git). In this way, the archive will still be always the same for a given commit
+        // (achieving reproducibility), but it will also change between different commits and
+        // Rust versions, so that it won't break mtime-based caches.
+        //
+        // Note that this only overrides the mtime of files, not directories, due to the
+        // limitations of the tarballer tool. Directories will have their mtime set to 2006.
+
+        // Get the UTC timestamp of the last git commit, if we're under git.
+        // We need to use UTC, so that anyone who tries to rebuild from the same commit
+        // gets the same timestamp.
+        if self.builder.rust_info().is_managed_git_subrepository() {
+            // %ct means committer date
+            let timestamp = helpers::output(
+                &mut helpers::git(Some(&self.builder.src))
+                    .arg("log")
+                    .arg("-1")
+                    .arg("--format=%ct")
+                    .command,
+            );
+            cmd.args(["--override-file-mtime", timestamp.trim()]);
+        }
+
+        cmd.run(self.builder);
 
         // Ensure there are no symbolic links in the tarball. In particular,
         // rustup-toolchain-install-master and most versions of Windows can't handle symbolic links.
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh
index e0c008b76fa..4a42f5da29f 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 # ignore-tidy-linelength
 
-set -ex
+set -eux
 
 hide_output() {
   set +x
@@ -20,6 +20,22 @@ exit 1
   set -x
 }
 
+# Download, verify SHA512, and remove the downloaded file
+# Usage: <file name> <url> <file sha> <full tar command using fname>
+download() {
+  fname="$1"
+  shift
+  url="$1"
+  shift
+  sha="$1"
+  shift
+
+  curl "$url" -o "$fname"
+  echo "$sha  $fname" | shasum -a 512 --check || exit 1
+  "$@"
+  rm "$fname"
+}
+
 mkdir netbsd
 cd netbsd
 
@@ -27,17 +43,31 @@ mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot
 
 # URL=https://ci-mirrors.rust-lang.org/rustc
 
-SOURCE_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/source/sets
-curl $SOURCE_URL/src.tgz | tar xzf -
-curl $SOURCE_URL/gnusrc.tgz | tar xzf -
-curl $SOURCE_URL/sharesrc.tgz | tar xzf -
-curl $SOURCE_URL/syssrc.tgz | tar xzf -
-
-BINARY_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/amd64/binary/sets
-curl $BINARY_URL/base.tar.xz | \
-  tar xJf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib
-curl $BINARY_URL/comp.tar.xz | \
-  tar xJf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib
+# Hashes come from https://cdn.netbsd.org/pub/NetBSD/security/hashes/NetBSD-9.0_hashes.asc
+SRC_SHA=2c791ae009a6929c6fc893ec5df7e62910ee8207e0b2159d6937309c03efe175b6ae1e445829a13d041b6851334ad35c521f2fa03c97675d4a05f1fafe58ede0
+GNUSRC_SHA=3710085a73feecf6a843415271ec794c90146b03f6bbd30f07c9e0c79febf8995d557e40194f1e05db655e4f5ef2fae97563f8456fceaae65d4ea98857a83b1c
+SHARESRC_SHA=f080776ed82c3ac5d6272dee39746f87897d8e6984996caf5bf6d87bf11d9c9e0c1ad5c437c21258bd278bb6fd76974946e878f548517885f71c556096231369
+SYSSRC_SHA=60b9ddf4cc6402256473e2e1eefeabd9001aa4e205208715ecc6d6fc3f5b400e469944580077271b8e80562a4c2f601249e69e07a504f46744e0c50335f1cbf1
+BASE_SHA=b5926b107cebf40c3c19b4f6cd039b610987dd7f819e7cdde3bd1e5230a856906e7930b15ab242d52ced9f0bda01d574be59488b8dbb95fa5df2987d0a70995f
+COMP_SHA=38ea54f30d5fc2afea87e5096f06873e00182789e8ad9cec0cb3e9f7c538c1aa4779e63fd401a36ba02676158e83fa5c95e8e87898db59c1914fb206aecd82d2
+
+# FIXME: the archive URL is being used temporarily while the CDN is down.
+# We should serve this from our own CDN
+# SOURCE_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/source/sets
+SOURCE_URL=http://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/source/sets
+download src.tgz "$SOURCE_URL/src.tgz" "$SRC_SHA" tar xzf src.tgz
+download gnusrc.tgz "$SOURCE_URL/gnusrc.tgz" "$GNUSRC_SHA" tar xzf gnusrc.tgz
+download sharesrc.tgz "$SOURCE_URL/sharesrc.tgz" "$SHARESRC_SHA" tar xzf sharesrc.tgz
+download syssrc.tgz "$SOURCE_URL/syssrc.tgz" "$SYSSRC_SHA" tar xzf syssrc.tgz
+
+# FIXME: the archive URL is being used temporarily while the CDN is down.
+# We should serve this from our own CDN
+# BINARY_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/amd64/binary/sets
+BINARY_URL=http://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/amd64/binary/sets
+download base.tar.xz "$BINARY_URL/base.tar.xz" "$BASE_SHA" \
+  tar xJf base.tar.xz -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib
+download comp.tar.xz "$BINARY_URL/comp.tar.xz" "$COMP_SHA" \
+  tar xJf comp.tar.xz -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib
 
 cd usr/src
 
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index a4c59b3067e..695b8b4c0d9 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -93,8 +93,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
     docker --version
 
     REGISTRY=ghcr.io
-    # PR CI runs on rust-lang, but we want to use the cache from rust-lang-ci
-    REGISTRY_USERNAME=rust-lang-ci
+    REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER}
     # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup
     IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum}
     # Tag used to cache the Docker build
diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py
index 6db25ff1a80..00269e68422 100755
--- a/src/ci/docker/scripts/fuchsia-test-runner.py
+++ b/src/ci/docker/scripts/fuchsia-test-runner.py
@@ -8,8 +8,6 @@ https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-unk
 """
 
 import argparse
-from concurrent.futures import ThreadPoolExecutor
-from dataclasses import dataclass
 import glob
 import io
 import json
@@ -20,6 +18,8 @@ import shlex
 import shutil
 import subprocess
 import sys
+from concurrent.futures import ThreadPoolExecutor
+from dataclasses import dataclass
 from pathlib import Path
 from typing import ClassVar, List, Optional
 
@@ -42,12 +42,8 @@ def check_call_with_logging(
                 for line in pipe:
                     handler(line.rstrip())
 
-            executor_out = executor.submit(
-                exhaust_pipe, stdout_handler, process.stdout
-            )
-            executor_err = executor.submit(
-                exhaust_pipe, stderr_handler, process.stderr
-            )
+            executor_out = executor.submit(exhaust_pipe, stdout_handler, process.stdout)
+            executor_err = executor.submit(exhaust_pipe, stderr_handler, process.stderr)
             executor_out.result()
             executor_err.result()
     retcode = process.poll()
@@ -203,9 +199,7 @@ class TestEnvironment:
             raise Exception(f"Unreadable build-id for binary {binary}")
         data = json.loads(process.stdout)
         if len(data) != 1:
-            raise Exception(
-                f"Unreadable output from llvm-readelf for binary {binary}"
-            )
+            raise Exception(f"Unreadable output from llvm-readelf for binary {binary}")
         notes = data[0]["Notes"]
         for note in notes:
             note_section = note["NoteSection"]
@@ -265,19 +259,10 @@ class TestEnvironment:
     def setup_logging(self, log_to_file=False):
         fs = logging.Formatter("%(asctime)s %(levelname)s:%(name)s:%(message)s")
         if log_to_file:
-            logfile_handler = logging.FileHandler(
-                self.tmp_dir().joinpath("log")
-            )
+            logfile_handler = logging.FileHandler(self.tmp_dir().joinpath("log"))
             logfile_handler.setLevel(logging.DEBUG)
             logfile_handler.setFormatter(fs)
             logging.getLogger().addHandler(logfile_handler)
-        stream_handler = logging.StreamHandler(sys.stdout)
-        stream_handler.setFormatter(fs)
-        if self.verbose:
-            stream_handler.setLevel(logging.DEBUG)
-        else:
-            stream_handler.setLevel(logging.INFO)
-        logging.getLogger().addHandler(stream_handler)
         logging.getLogger().setLevel(logging.DEBUG)
 
     @property
@@ -454,9 +439,7 @@ class TestEnvironment:
         # Initialize temp directory
         os.makedirs(self.tmp_dir(), exist_ok=True)
         if len(os.listdir(self.tmp_dir())) != 0:
-            raise Exception(
-                f"Temp directory is not clean (in {self.tmp_dir()})"
-            )
+            raise Exception(f"Temp directory is not clean (in {self.tmp_dir()})")
         self.setup_logging(log_to_file=True)
         os.mkdir(self.output_dir)
 
@@ -493,9 +476,7 @@ class TestEnvironment:
             shutil.rmtree(self.local_pb_path, ignore_errors=True)
 
             # Look up the product bundle transfer manifest.
-            self.env_logger.info(
-                "Looking up the product bundle transfer manifest..."
-            )
+            self.env_logger.info("Looking up the product bundle transfer manifest...")
             product_name = "minimal." + self.triple_to_arch(self.target)
             sdk_version = self.read_sdk_version()
 
@@ -517,9 +498,7 @@ class TestEnvironment:
             )
 
             try:
-                transfer_manifest_url = json.loads(output)[
-                    "transfer_manifest_url"
-                ]
+                transfer_manifest_url = json.loads(output)["transfer_manifest_url"]
             except Exception as e:
                 print(e)
                 raise Exception("Unable to parse transfer manifest") from e
@@ -769,9 +748,7 @@ class TestEnvironment:
             # Use /tmp as the test temporary directory
             env_vars += '\n            "RUST_TEST_TMPDIR=/tmp",'
 
-            cml.write(
-                self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name)
-            )
+            cml.write(self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name))
 
         runner_logger.info("Compiling CML...")
 
@@ -922,20 +899,16 @@ class TestEnvironment:
 
         if stdout_path is not None:
             if not os.path.exists(stdout_path):
-                runner_logger.error(
-                    f"stdout file {stdout_path} does not exist."
-                )
+                runner_logger.error(f"stdout file {stdout_path} does not exist.")
             else:
                 with open(stdout_path, encoding="utf-8", errors="ignore") as f:
-                    runner_logger.info(f.read())
+                    sys.stdout.write(f.read())
         if stderr_path is not None:
             if not os.path.exists(stderr_path):
-                runner_logger.error(
-                    f"stderr file {stderr_path} does not exist."
-                )
+                runner_logger.error(f"stderr file {stderr_path} does not exist.")
             else:
                 with open(stderr_path, encoding="utf-8", errors="ignore") as f:
-                    runner_logger.error(f.read())
+                    sys.stderr.write(f.read())
 
         runner_logger.info("Done!")
         return return_code
@@ -1037,7 +1010,7 @@ class TestEnvironment:
                 f"--symbol-path={self.rust_dir}/lib/rustlib/{self.target}/lib",
             ]
 
-      # Add rust source if it's available
+        # Add rust source if it's available
         rust_src_map = None
         if args.rust_src is not None:
             # This matches the remapped prefix used by compiletest. There's no
@@ -1210,7 +1183,7 @@ def main():
     start_parser.add_argument(
         "--use-local-product-bundle-if-exists",
         help="if the product bundle already exists in the local path, use "
-            "it instead of downloading it again",
+        "it instead of downloading it again",
         action="store_true",
     )
     start_parser.set_defaults(func=start)
@@ -1246,9 +1219,7 @@ def main():
     )
     cleanup_parser.set_defaults(func=cleanup)
 
-    syslog_parser = subparsers.add_parser(
-        "syslog", help="prints the device syslog"
-    )
+    syslog_parser = subparsers.add_parser("syslog", help="prints the device syslog")
     syslog_parser.set_defaults(func=syslog)
 
     debug_parser = subparsers.add_parser(
diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/calculate-job-matrix.py
index 4f9bc39a628..d03bbda1008 100755
--- a/src/ci/github-actions/calculate-job-matrix.py
+++ b/src/ci/github-actions/calculate-job-matrix.py
@@ -91,21 +91,17 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]:
     if ctx.event_name == "pull_request":
         return PRRunType()
     elif ctx.event_name == "push":
-        old_bors_try_build = (
-            ctx.ref in ("refs/heads/try", "refs/heads/try-perf") and
-            ctx.repository == "rust-lang-ci/rust"
+        try_build = ctx.ref in (
+            "refs/heads/try",
+            "refs/heads/try-perf",
+            "refs/heads/automation/bors/try"
         )
-        new_bors_try_build = (
-            ctx.ref == "refs/heads/automation/bors/try" and
-            ctx.repository == "rust-lang/rust"
-        )
-        try_build = old_bors_try_build or new_bors_try_build
 
         if try_build:
             jobs = get_custom_jobs(ctx)
             return TryRunType(custom_jobs=jobs)
 
-        if ctx.ref == "refs/heads/auto" and ctx.repository == "rust-lang-ci/rust":
+        if ctx.ref == "refs/heads/auto":
             return AutoRunType()
 
     return None
diff --git a/src/doc/book b/src/doc/book
-Subproject 45c1a6d69edfd1fc91fb7504cb73958dbd09441
+Subproject f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc6
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject cb58c430b4e8054c2cb81d2d4434092c482a93d
+Subproject 941db8b3df45fd46cd87b50a5c86714b91dcde9
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 0b805c65804019b0ac8f2fe3117afad82a6069b
+Subproject 1ae3deebc3ac16e276b6558e01420f8e605def0
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject b1d97bd6113aba732b2091ce093c76f2d05bb8a
+Subproject 658c6c27cb975b92227936024816986c2d3716f
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject aec82168dd3121289a194b381f56076fc789a4d
+Subproject d6e3a32a557db5902e714604def8015d6bb7e0f
diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md
index 2b3d15e93c8..c3eda26ca8e 100644
--- a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md
+++ b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md
@@ -107,7 +107,7 @@ flag, for example:
 
 Users need to install or built wasi-sdk since release 20.0
 https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-20
-and specify path to *wasi-root* `.cargo/config.toml`
+and specify path to *wasi-root* `config.toml`
 
 ```toml
 [target.wasm32-wasip1-threads]
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index 1733c8fc9a2..4a1c0916253 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -80,7 +80,8 @@ pub struct BigX;
 Then, when looking for it through the `rustdoc` search, if you enter "x" or
 "big", search will show the `BigX` struct first.
 
-There are some limitations on the doc alias names though: you can't use `"` or whitespace.
+There are some limitations on the doc alias names though: they cannot contain quotes (`'`, `"`)
+or most whitespace. ASCII space is allowed if it does not start or end the alias.
 
 You can add multiple aliases at the same time by using a list:
 
diff --git a/src/doc/style-guide/src/nightly.md b/src/doc/style-guide/src/nightly.md
index 66e7fa3c9f8..d870edf1888 100644
--- a/src/doc/style-guide/src/nightly.md
+++ b/src/doc/style-guide/src/nightly.md
@@ -5,3 +5,15 @@ This chapter documents style and formatting for nightly-only syntax. The rest of
 Style and formatting for nightly-only syntax should be removed from this chapter and integrated into the appropriate sections of the style guide at the time of stabilization.
 
 There is no guarantee of the stability of this chapter in contrast to the rest of the style guide. Refer to the style team policy for nightly formatting procedure regarding breaking changes to this chapter.
+
+### `feature(precise_capturing)`
+
+A `use<'a, T>` precise capturing bound is formatted as if it were a single path segment with non-turbofished angle-bracketed args, like a trait bound whose identifier is `use`.
+
+```
+fn foo() -> impl Sized + use<'a> {}
+
+// is formatted analogously to:
+
+fn foo() -> impl Sized + Use<'a> {}
+```
diff --git a/src/doc/unstable-book/src/compiler-flags/verbose-asm.md b/src/doc/unstable-book/src/compiler-flags/verbose-asm.md
new file mode 100644
index 00000000000..84eb90a14cf
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/verbose-asm.md
@@ -0,0 +1,70 @@
+# `verbose-asm`
+
+The tracking issue for this feature is: [#126802](https://github.com/rust-lang/rust/issues/126802).
+
+------------------------
+
+This enables passing `-Zverbose-asm` to get contextual comments added by LLVM.
+
+Sample code:
+
+```rust
+#[no_mangle]
+pub fn foo(a: i32, b: i32) -> i32 {
+    a + b
+}
+```
+
+Default output:
+
+```asm
+foo:
+        push    rax
+        add     edi, esi
+        mov     dword ptr [rsp + 4], edi
+        seto    al
+        jo      .LBB0_2
+        mov     eax, dword ptr [rsp + 4]
+        pop     rcx
+        ret
+.LBB0_2:
+        lea     rdi, [rip + .L__unnamed_1]
+        mov     rax, qword ptr [rip + core::panicking::panic_const::panic_const_add_overflow::h9c85248fe0d735b2@GOTPCREL]
+        call    rax
+
+.L__unnamed_2:
+        .ascii  "/app/example.rs"
+
+.L__unnamed_1:
+        .quad   .L__unnamed_2
+        .asciz  "\017\000\000\000\000\000\000\000\004\000\000\000\005\000\000"
+```
+
+With `-Zverbose-asm`:
+
+```asm
+foo:                                    # @foo
+# %bb.0:
+        push    rax
+        add     edi, esi
+        mov     dword ptr [rsp + 4], edi        # 4-byte Spill
+        seto    al
+        jo      .LBB0_2
+# %bb.1:
+        mov     eax, dword ptr [rsp + 4]        # 4-byte Reload
+        pop     rcx
+        ret
+.LBB0_2:
+        lea     rdi, [rip + .L__unnamed_1]
+        mov     rax, qword ptr [rip + core::panicking::panic_const::panic_const_add_overflow::h9c85248fe0d735b2@GOTPCREL]
+        call    rax
+                                        # -- End function
+.L__unnamed_2:
+        .ascii  "/app/example.rs"
+
+.L__unnamed_1:
+        .quad   .L__unnamed_2
+        .asciz  "\017\000\000\000\000\000\000\000\004\000\000\000\005\000\000"
+
+                                        # DW_AT_external
+```
diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis
index 8c16a562e34..49e0ce319ef 100644
--- a/src/etc/natvis/intrinsic.natvis
+++ b/src/etc/natvis/intrinsic.natvis
@@ -33,6 +33,32 @@
       </ArrayItems>
     </Expand>
   </Type>
+  <Type Name="f16">
+    <Intrinsic Name="sign_mask" Expression="(unsigned __int16) 0x8000" />
+    <Intrinsic Name="exponent_mask" Expression="(unsigned __int16) 0x7c00" />
+    <Intrinsic Name="significand_mask" Expression="(unsigned __int16) 0x03ff" />
+    <Intrinsic Name="sign_bit" Expression="(unsigned __int16) (bits &amp; sign_mask())" />
+    <Intrinsic Name="exponent_bits" Expression="(unsigned __int16) (bits &amp; exponent_mask())" />
+    <Intrinsic Name="significand_bits" Expression="(unsigned __int16) (bits &amp; significand_mask())" />
+
+    <Intrinsic Name="if_set" Expression="(bits &amp; mask) != 0 ? value : 1.0">
+      <Parameter Name="mask" Type="unsigned __int16" />
+      <Parameter Name="value" Type="float" />
+    </Intrinsic>
+    <!-- Calculates 2**exp without needing a pow function. Each float in if_set() is the square of the previous float. 32768 == 2.pow(bias), bias == 15 -->
+    <Intrinsic Name="two_pow_exponent" Expression="if_set(0x0400, 2.0) * if_set(0x0800, 4.0) * if_set(0x1000, 16.0) * if_set(0x2000, 256.0) * if_set(0x4000, 65536.0) / 32768.0" />
+    <!-- Calculates 0.significand, without any implicit bit. 1024 == 2.pow(explicit significand width), explicit significand width == 10 -->
+    <Intrinsic Name="raw_significand" Expression="((float) significand_bits()) / 1024.0" />
+    <Intrinsic Name="sign" Expression="sign_bit() == 0 ? 1.0 : -1.0" />
+
+    <DisplayString Condition="bits == 0x7c00">inf</DisplayString>
+    <DisplayString Condition="bits == 0xfc00">-inf</DisplayString>
+    <DisplayString Condition="exponent_bits() == exponent_mask()">NaN</DisplayString>
+    <!-- Subnormal or zero (16384 == 2.pow(bias - 1), bias - 1 == 14) -->
+    <DisplayString Condition="exponent_bits() == 0">{(float) (sign() * raw_significand() / 16384.0)}</DisplayString>
+    <!-- Normal -->
+    <DisplayString>{(float) (sign() * (raw_significand() + 1.0) * two_pow_exponent())}</DisplayString>
+  </Type>
   <Type Name="tuple$&lt;&gt;">
     <DisplayString>()</DisplayString>
   </Type>
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 31222f213d8..51fb126cb34 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -13,6 +13,7 @@ base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
 minifier = "0.3.0"
+pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false }
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
 serde_json = "1.0"
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b5660cd8492..aa596897fc4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1404,8 +1404,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
 
             let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
             if let ty::TraitContainer = assoc_item.container {
-                let bounds =
-                    tcx.explicit_item_bounds(assoc_item.def_id).instantiate_identity_iter_copied();
+                let bounds = tcx.explicit_item_bounds(assoc_item.def_id).iter_identity_copied();
                 predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
             }
             let mut generics = clean_ty_generics(
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 9050a1c1207..fe01d17b08a 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1286,7 +1286,7 @@ impl GenericBound {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct Lifetime(pub Symbol);
 
 impl Lifetime {
@@ -2557,7 +2557,7 @@ pub(crate) struct ProcMacro {
 /// * the `A: Bound` in `Trait<A: Bound>`
 /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
 /// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
-/// * the `f(): Bound` in `Trait<f(): Bound>` (feature `return_type_notation`)
+/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct AssocItemConstraint {
     pub(crate) assoc: PathSegment,
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index bae929c64ea..a7f0df5afa9 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -54,7 +54,8 @@ use crate::html::render::small_url_encode;
 use crate::html::toc::TocBuilder;
 
 use pulldown_cmark::{
-    html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag,
+    html, BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter,
+    Options, Parser, Tag, TagEnd,
 };
 
 #[cfg(test)]
@@ -230,7 +231,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
         let mut original_text = String::new();
         for event in &mut self.inner {
             match event {
-                Event::End(Tag::CodeBlock(..)) => break,
+                Event::End(TagEnd::CodeBlock) => break,
                 Event::Text(ref s) => {
                     original_text.push_str(s);
                 }
@@ -359,16 +360,17 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
         match &mut event {
             // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]`
             // Remove any disambiguator.
-            Some(Event::Start(Tag::Link(
+            Some(Event::Start(Tag::Link {
                 // [fn@f] or [fn@f][]
-                LinkType::ShortcutUnknown | LinkType::CollapsedUnknown,
-                dest,
+                link_type: LinkType::ShortcutUnknown | LinkType::CollapsedUnknown,
+                dest_url,
                 title,
-            ))) => {
-                debug!("saw start of shortcut link to {dest} with title {title}");
+                ..
+            })) => {
+                debug!("saw start of shortcut link to {dest_url} with title {title}");
                 // If this is a shortcut link, it was resolved by the broken_link_callback.
                 // So the URL will already be updated properly.
-                let link = self.links.iter().find(|&link| *link.href == **dest);
+                let link = self.links.iter().find(|&link| *link.href == **dest_url);
                 // Since this is an external iterator, we can't replace the inner text just yet.
                 // Store that we saw a link so we know to replace it later.
                 if let Some(link) = link {
@@ -381,16 +383,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
                 }
             }
             // Now that we're done with the shortcut link, don't replace any more text.
-            Some(Event::End(Tag::Link(
-                LinkType::ShortcutUnknown | LinkType::CollapsedUnknown,
-                dest,
-                _,
-            ))) => {
-                debug!("saw end of shortcut link to {dest}");
-                if self.links.iter().any(|link| *link.href == **dest) {
-                    assert!(self.shortcut_link.is_some(), "saw closing link without opening tag");
-                    self.shortcut_link = None;
-                }
+            Some(Event::End(TagEnd::Link)) if self.shortcut_link.is_some() => {
+                debug!("saw end of shortcut link");
+                self.shortcut_link = None;
             }
             // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link.
             // [`fn@f`]
@@ -433,9 +428,11 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
             }
             // If this is a link, but not a shortcut link,
             // replace the URL, since the broken_link_callback was not called.
-            Some(Event::Start(Tag::Link(_, dest, title))) => {
-                if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) {
-                    *dest = CowStr::Borrowed(link.href.as_ref());
+            Some(Event::Start(Tag::Link { dest_url, title, .. })) => {
+                if let Some(link) =
+                    self.links.iter().find(|&link| *link.original_text == **dest_url)
+                {
+                    *dest_url = CowStr::Borrowed(link.href.as_ref());
                     if title.is_empty() && !link.tooltip.is_empty() {
                         *title = CowStr::Borrowed(link.tooltip.as_ref());
                     }
@@ -477,9 +474,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for TableWrapper<'a, I> {
                 self.stored_events.push_back(Event::Start(Tag::Table(t)));
                 Event::Html(CowStr::Borrowed("<div>"))
             }
-            Event::End(Tag::Table(t)) => {
+            Event::End(TagEnd::Table) => {
                 self.stored_events.push_back(Event::Html(CowStr::Borrowed("</div>")));
-                Event::End(Tag::Table(t))
+                Event::End(TagEnd::Table)
             }
             e => e,
         })
@@ -519,11 +516,11 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
         }
 
         let event = self.inner.next();
-        if let Some((Event::Start(Tag::Heading(level, _, _)), _)) = event {
+        if let Some((Event::Start(Tag::Heading { level, .. }), _)) = event {
             let mut id = String::new();
             for event in &mut self.inner {
                 match &event.0 {
-                    Event::End(Tag::Heading(..)) => break,
+                    Event::End(TagEnd::Heading(_)) => break,
                     Event::Text(text) | Event::Code(text) => {
                         id.extend(text.chars().filter_map(slugify));
                         self.buf.push_back(event);
@@ -566,27 +563,27 @@ impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> {
     }
 }
 
-fn check_if_allowed_tag(t: &Tag<'_>) -> bool {
+fn check_if_allowed_tag(t: &TagEnd) -> bool {
     matches!(
         t,
-        Tag::Paragraph
-            | Tag::Emphasis
-            | Tag::Strong
-            | Tag::Strikethrough
-            | Tag::Link(..)
-            | Tag::BlockQuote
+        TagEnd::Paragraph
+            | TagEnd::Emphasis
+            | TagEnd::Strong
+            | TagEnd::Strikethrough
+            | TagEnd::Link
+            | TagEnd::BlockQuote
     )
 }
 
-fn is_forbidden_tag(t: &Tag<'_>) -> bool {
+fn is_forbidden_tag(t: &TagEnd) -> bool {
     matches!(
         t,
-        Tag::CodeBlock(_)
-            | Tag::Table(_)
-            | Tag::TableHead
-            | Tag::TableRow
-            | Tag::TableCell
-            | Tag::FootnoteDefinition(_)
+        TagEnd::CodeBlock
+            | TagEnd::Table
+            | TagEnd::TableHead
+            | TagEnd::TableRow
+            | TagEnd::TableCell
+            | TagEnd::FootnoteDefinition
     )
 }
 
@@ -604,12 +601,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
             let mut is_start = true;
             let is_allowed_tag = match event {
                 Event::Start(ref c) => {
-                    if is_forbidden_tag(c) {
+                    if is_forbidden_tag(&c.to_end()) {
                         self.skipped_tags += 1;
                         return None;
                     }
                     self.depth += 1;
-                    check_if_allowed_tag(c)
+                    check_if_allowed_tag(&c.to_end())
                 }
                 Event::End(ref c) => {
                     if is_forbidden_tag(c) {
@@ -633,7 +630,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
                 if is_start {
                     Some(Event::Start(Tag::Paragraph))
                 } else {
-                    Some(Event::End(Tag::Paragraph))
+                    Some(Event::End(TagEnd::Paragraph))
                 }
             } else {
                 Some(event)
@@ -679,7 +676,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
                 Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => {
                     let mut content = Vec::new();
                     for (event, _) in &mut self.inner {
-                        if let Event::End(Tag::FootnoteDefinition(..)) = event {
+                        if let Event::End(TagEnd::FootnoteDefinition) = event {
                             break;
                         }
                         content.push(event);
@@ -696,7 +693,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
                         for (mut content, id) in v {
                             write!(ret, "<li id=\"fn{id}\">").unwrap();
                             let mut is_paragraph = false;
-                            if let Some(&Event::End(Tag::Paragraph)) = content.last() {
+                            if let Some(&Event::End(TagEnd::Paragraph)) = content.last() {
                                 content.pop();
                                 is_paragraph = true;
                             }
@@ -806,7 +803,7 @@ pub(crate) fn find_codes<T: doctest::DoctestVisitor>(
                 tests.visit_test(text, block_info, line);
                 prev_offset = offset.start;
             }
-            Event::Start(Tag::Heading(level, _, _)) => {
+            Event::Start(Tag::Heading { level, .. }) => {
                 register_header = Some(level as u32);
             }
             Event::Text(ref s) if register_header.is_some() => {
@@ -1432,7 +1429,7 @@ impl MarkdownItemInfo<'_> {
 
         // Treat inline HTML as plain text.
         let p = p.map(|event| match event.0 {
-            Event::Html(text) => (Event::Text(text), event.1),
+            Event::Html(text) | Event::InlineHtml(text) => (Event::Text(text), event.1),
             _ => event,
         });
 
@@ -1442,7 +1439,7 @@ impl MarkdownItemInfo<'_> {
         let p = Footnotes::new(p);
         let p = TableWrapper::new(p.map(|(ev, _)| ev));
         let p = p.filter(|event| {
-            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph))
+            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
         });
         html::push_html(&mut s, p);
 
@@ -1472,7 +1469,7 @@ impl MarkdownSummaryLine<'_> {
         let mut s = String::new();
 
         let without_paragraphs = LinkReplacer::new(&mut summary, links).filter(|event| {
-            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph))
+            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
         });
 
         html::push_html(&mut s, without_paragraphs);
@@ -1544,8 +1541,8 @@ fn markdown_summary_with_limit(
                 _ => {}
             },
             Event::End(tag) => match tag {
-                Tag::Emphasis | Tag::Strong => buf.close_tag(),
-                Tag::Paragraph | Tag::Heading(..) => return ControlFlow::Break(()),
+                TagEnd::Emphasis | TagEnd::Strong => buf.close_tag(),
+                TagEnd::Paragraph | TagEnd::Heading(_) => return ControlFlow::Break(()),
                 _ => {}
             },
             Event::HardBreak | Event::SoftBreak => buf.push(" ")?,
@@ -1605,8 +1602,8 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
             }
             Event::HardBreak | Event::SoftBreak => s.push(' '),
             Event::Start(Tag::CodeBlock(..)) => break,
-            Event::End(Tag::Paragraph) => break,
-            Event::End(Tag::Heading(..)) => break,
+            Event::End(TagEnd::Paragraph) => break,
+            Event::End(TagEnd::Heading(..)) => break,
             _ => (),
         }
     }
@@ -1765,7 +1762,7 @@ pub(crate) fn markdown_links<'md, R>(
 
     while let Some((event, span)) = event_iter.next() {
         match event {
-            Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
+            Event::Start(Tag::Link { link_type, dest_url, .. }) if may_be_doc_link(link_type) => {
                 let range = match link_type {
                     // Link is pulled from the link itself.
                     LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => {
@@ -1775,7 +1772,7 @@ pub(crate) fn markdown_links<'md, R>(
                     LinkType::Inline => span_for_offset_backward(span, b'(', b')'),
                     // Link is pulled from elsewhere in the document.
                     LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => {
-                        span_for_link(&dest, span)
+                        span_for_link(&dest_url, span)
                     }
                     LinkType::Autolink | LinkType::Email => unreachable!(),
                 };
@@ -1795,7 +1792,7 @@ pub(crate) fn markdown_links<'md, R>(
 
                 if let Some(link) = preprocess_link(MarkdownLink {
                     kind: link_type,
-                    link: dest.into_string(),
+                    link: dest_url.into_string(),
                     display_text,
                     range,
                 }) {
@@ -1810,8 +1807,8 @@ pub(crate) fn markdown_links<'md, R>(
 }
 
 /// Collects additional data of link.
-fn collect_link_data<'input, 'callback>(
-    event_iter: &mut OffsetIter<'input, 'callback>,
+fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
+    event_iter: &mut OffsetIter<'input, F>,
 ) -> Option<String> {
     let mut display_text: Option<String> = None;
     let mut append_text = |text: CowStr<'_>| {
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index c806bf1cc66..8fd56eae37f 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -507,8 +507,7 @@ else if (window.initSearch) window.initSearch(searchIndex);
                 // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress.
                 let Some(impl_did) = impl_item_id.as_def_id() else { continue };
                 let for_ty = self.cx.tcx().type_of(impl_did).skip_binder();
-                let reject_cx =
-                    DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey };
+                let reject_cx = DeepRejectCtxt::new(self.cx.tcx(), TreatParams::AsCandidateKey);
                 if !reject_cx.types_may_unify(aliased_ty, for_ty) {
                     continue;
                 }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index a0ab262bf0b..86af38f3ee7 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -3293,10 +3293,9 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         }
         // call after consuming `{`
         decodeList() {
-            const cb = "}".charCodeAt(0);
             let c = this.string.charCodeAt(this.offset);
             const ret = [];
-            while (c !== cb) {
+            while (c !== 125) { // 125 = "}"
                 ret.push(this.decode());
                 c = this.string.charCodeAt(this.offset);
             }
@@ -3305,14 +3304,13 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         }
         // consumes and returns a list or integer
         decode() {
-            const [ob, la] = ["{", "`"].map(c => c.charCodeAt(0));
             let n = 0;
             let c = this.string.charCodeAt(this.offset);
-            if (c === ob) {
+            if (c === 123) { // 123 = "{"
                 this.offset += 1;
                 return this.decodeList();
             }
-            while (c < la) {
+            while (c < 96) { // 96 = "`"
                 n = (n << 4) | (c & 0xF);
                 this.offset += 1;
                 c = this.string.charCodeAt(this.offset);
@@ -3325,15 +3323,14 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         }
         next() {
             const c = this.string.charCodeAt(this.offset);
-            const [zero, ua, la] = ["0", "@", "`"].map(c => c.charCodeAt(0));
             // sixteen characters after "0" are backref
-            if (c >= zero && c < ua) {
+            if (c >= 48 && c < 64) { // 48 = "0", 64 = "@"
                 this.offset += 1;
-                return this.backrefQueue[c - zero];
+                return this.backrefQueue[c - 48];
             }
             // special exception: 0 doesn't use backref encoding
             // it's already one character, and it's always nullish
-            if (c === la) {
+            if (c === 96) { // 96 = "`"
                 this.offset += 1;
                 return this.cons(0);
             }
@@ -3472,7 +3469,6 @@ ${item.displayPath}<span class="${type}">${name}</span>\
         searchIndex = [];
         searchIndexDeprecated = new Map();
         searchIndexEmptyDesc = new Map();
-        const charA = "A".charCodeAt(0);
         let currentIndex = 0;
         let id = 0;
 
@@ -3639,7 +3635,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
                 // object defined above.
                 const row = {
                     crate,
-                    ty: itemTypes.charCodeAt(i) - charA,
+                    ty: itemTypes.charCodeAt(i) - 65, // 65 = "A"
                     name: itemNames[i],
                     path,
                     descShard,
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index b965ab019cc..5111e363c52 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -10,6 +10,7 @@ use rustc_ast::ast;
 use rustc_attr::DeprecatedSince;
 use rustc_hir::{def::CtorKind, def::DefKind, def_id::DefId};
 use rustc_metadata::rendered_const;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::{Pos, Symbol};
@@ -512,9 +513,15 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
                     })
                     .collect(),
             },
-            RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
+            RegionPredicate { lifetime, bounds } => WherePredicate::LifetimePredicate {
                 lifetime: convert_lifetime(lifetime),
-                bounds: bounds.into_tcx(tcx),
+                outlives: bounds
+                    .iter()
+                    .map(|bound| match bound {
+                        clean::GenericBound::Outlives(lt) => convert_lifetime(*lt),
+                        _ => bug!("found non-outlives-bound on lifetime predicate"),
+                    })
+                    .collect(),
             },
             EqPredicate { lhs, rhs } => {
                 WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) }
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index dd2bb47e592..8eaca70eaff 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -196,6 +196,14 @@ declare_rustdoc_lint! {
     "detects redundant explicit links in doc comments"
 }
 
+declare_rustdoc_lint! {
+    /// This compatibility lint checks for Markdown syntax that works in the old engine but not
+    /// the new one.
+    UNPORTABLE_MARKDOWN,
+    Warn,
+    "detects markdown that is interpreted differently in different parser"
+}
+
 pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
     vec![
         BROKEN_INTRA_DOC_LINKS,
@@ -209,6 +217,7 @@ pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
         MISSING_CRATE_LEVEL_DOCS,
         UNESCAPED_BACKTICKS,
         REDUNDANT_EXPLICIT_LINKS,
+        UNPORTABLE_MARKDOWN,
     ]
 });
 
diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs
index c6d5b7bd346..bc804a340bf 100644
--- a/src/librustdoc/passes/lint.rs
+++ b/src/librustdoc/passes/lint.rs
@@ -6,6 +6,7 @@ mod check_code_block_syntax;
 mod html_tags;
 mod redundant_explicit_links;
 mod unescaped_backticks;
+mod unportable_markdown;
 
 use super::Pass;
 use crate::clean::*;
@@ -31,6 +32,7 @@ impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> {
         html_tags::visit_item(self.cx, item);
         unescaped_backticks::visit_item(self.cx, item);
         redundant_explicit_links::visit_item(self.cx, item);
+        unportable_markdown::visit_item(self.cx, item);
 
         self.visit_item_recur(item)
     }
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs
index 8f68f6ff476..a4ba718789c 100644
--- a/src/librustdoc/passes/lint/bare_urls.rs
+++ b/src/librustdoc/passes/lint/bare_urls.rs
@@ -19,22 +19,22 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
     };
     let dox = item.doc_value();
     if !dox.is_empty() {
-        let report_diag =
-            |cx: &DocContext<'_>, msg: &'static str, url: &str, range: Range<usize>| {
-                let sp =
-                    source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings)
-                        .unwrap_or_else(|| item.attr_span(cx.tcx));
-                cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| {
-                    lint.primary_message(msg)
-                        .note("bare URLs are not automatically turned into clickable links")
-                        .span_suggestion(
-                            sp,
-                            "use an automatic link instead",
-                            format!("<{url}>"),
-                            Applicability::MachineApplicable,
-                        );
-                });
-            };
+        let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range<usize>| {
+            let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings)
+                .unwrap_or_else(|| item.attr_span(cx.tcx));
+            cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| {
+                lint.primary_message(msg)
+                    .note("bare URLs are not automatically turned into clickable links")
+                    .multipart_suggestion(
+                        "use an automatic link instead",
+                        vec![
+                            (sp.shrink_to_lo(), "<".to_string()),
+                            (sp.shrink_to_hi(), ">".to_string()),
+                        ],
+                        Applicability::MachineApplicable,
+                    );
+            });
+        };
 
         let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter();
 
@@ -42,11 +42,11 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
             match event {
                 Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag),
                 // We don't want to check the text inside code blocks or links.
-                Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link(..))) => {
+                Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link { .. })) => {
                     while let Some((event, _)) = p.next() {
                         match event {
                             Event::End(end)
-                                if mem::discriminant(&end) == mem::discriminant(&tag) =>
+                                if mem::discriminant(&end) == mem::discriminant(&tag.to_end()) =>
                             {
                                 break;
                             }
@@ -74,17 +74,15 @@ fn find_raw_urls(
     cx: &DocContext<'_>,
     text: &str,
     range: Range<usize>,
-    f: &impl Fn(&DocContext<'_>, &'static str, &str, Range<usize>),
+    f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>),
 ) {
     trace!("looking for raw urls in {text}");
     // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
     for match_ in URL_REGEX.find_iter(text) {
-        let url = match_.as_str();
         let url_range = match_.range();
         f(
             cx,
             "this URL is not a hyperlink",
-            url,
             Range { start: range.start + url_range.start, end: range.start + url_range.end },
         );
     }
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
index a0064a90112..87dfa5d5389 100644
--- a/src/librustdoc/passes/lint/html_tags.rs
+++ b/src/librustdoc/passes/lint/html_tags.rs
@@ -4,7 +4,7 @@ use crate::clean::*;
 use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
 
-use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag};
+use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag, TagEnd};
 use rustc_resolve::rustdoc::source_span_for_markdown_range;
 
 use std::iter::Peekable;
@@ -140,10 +140,10 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
         for (event, range) in p {
             match event {
                 Event::Start(Tag::CodeBlock(_)) => in_code_block = true,
-                Event::Html(text) if !in_code_block => {
+                Event::Html(text) | Event::InlineHtml(text) if !in_code_block => {
                     extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag)
                 }
-                Event::End(Tag::CodeBlock(_)) => in_code_block = false,
+                Event::End(TagEnd::CodeBlock) => in_code_block = false,
                 _ => {}
             }
         }
diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs
index 7ab974046b9..b36b41c9f2d 100644
--- a/src/librustdoc/passes/lint/redundant_explicit_links.rs
+++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs
@@ -1,6 +1,8 @@
 use std::ops::Range;
 
-use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, OffsetIter, Parser, Tag};
+use pulldown_cmark::{
+    BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, OffsetIter, Parser, Tag,
+};
 use rustc_ast::NodeId;
 use rustc_errors::SuggestionStyle;
 use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res};
@@ -95,7 +97,7 @@ fn check_redundant_explicit_link<'md>(
 
     while let Some((event, link_range)) = offset_iter.next() {
         match event {
-            Event::Start(Tag::Link(link_type, dest, _)) => {
+            Event::Start(Tag::Link { link_type, dest_url, .. }) => {
                 let link_data = collect_link_data(&mut offset_iter);
 
                 if let Some(resolvable_link) = link_data.resolvable_link.as_ref() {
@@ -108,7 +110,7 @@ fn check_redundant_explicit_link<'md>(
                     }
                 }
 
-                let explicit_link = dest.to_string();
+                let explicit_link = dest_url.to_string();
                 let display_link = link_data.resolvable_link.clone()?;
 
                 if explicit_link.ends_with(&display_link) || display_link.ends_with(&explicit_link)
@@ -122,7 +124,7 @@ fn check_redundant_explicit_link<'md>(
                                 doc,
                                 resolutions,
                                 link_range,
-                                dest.to_string(),
+                                dest_url.to_string(),
                                 link_data,
                                 if link_type == LinkType::Inline {
                                     (b'(', b')')
@@ -139,7 +141,7 @@ fn check_redundant_explicit_link<'md>(
                                 doc,
                                 resolutions,
                                 link_range,
-                                &dest,
+                                &dest_url,
                                 link_data,
                             );
                         }
@@ -259,7 +261,9 @@ fn find_resolution(resolutions: &DocLinkResMap, path: &str) -> Option<Res<NodeId
 }
 
 /// Collects all necessary data of link.
-fn collect_link_data(offset_iter: &mut OffsetIter<'_, '_>) -> LinkData {
+fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
+    offset_iter: &mut OffsetIter<'input, F>,
+) -> LinkData {
     let mut resolvable_link = None;
     let mut resolvable_link_range = None;
     let mut display_link = String::new();
diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs
new file mode 100644
index 00000000000..5f185377634
--- /dev/null
+++ b/src/librustdoc/passes/lint/unportable_markdown.rs
@@ -0,0 +1,152 @@
+//! Detects specific markdown syntax that's different between pulldown-cmark
+//! 0.9 and 0.11.
+//!
+//! This is a mitigation for old parser bugs that affected some
+//! real crates' docs. The old parser claimed to comply with CommonMark,
+//! but it did not. These warnings will eventually be removed,
+//! though some of them may become Clippy lints.
+//!
+//! <https://github.com/rust-lang/rust/pull/121659#issuecomment-1992752820>
+//!
+//! <https://rustc-dev-guide.rust-lang.org/bug-fix-procedure.html#add-the-lint-to-the-list-of-removed-lists>
+
+use crate::clean::Item;
+use crate::core::DocContext;
+use pulldown_cmark as cmarkn;
+use pulldown_cmark_old as cmarko;
+use rustc_lint_defs::Applicability;
+use rustc_resolve::rustdoc::source_span_for_markdown_range;
+use std::collections::{BTreeMap, BTreeSet};
+
+pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
+    let tcx = cx.tcx;
+    let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else {
+        // If non-local, no need to check anything.
+        return;
+    };
+
+    let dox = item.doc_value();
+    if dox.is_empty() {
+        return;
+    }
+
+    // P1: unintended strikethrough was fixed by requiring single-tildes to flank
+    // the same way underscores do, so nothing is done here
+
+    // P2: block quotes without following space parsed wrong
+    //
+    // This is the set of starting points for block quotes with no space after
+    // the `>`. It is populated by the new parser, and if the old parser fails to
+    // clear it out, it'll produce a warning.
+    let mut spaceless_block_quotes = BTreeSet::new();
+
+    // P3: missing footnote references
+    //
+    // This is populated by listening for FootnoteReference from
+    // the new parser and old parser.
+    let mut missing_footnote_references = BTreeMap::new();
+    let mut found_footnote_references = BTreeSet::new();
+
+    // populate problem cases from new parser
+    {
+        pub fn main_body_opts_new() -> cmarkn::Options {
+            cmarkn::Options::ENABLE_TABLES
+                | cmarkn::Options::ENABLE_FOOTNOTES
+                | cmarkn::Options::ENABLE_STRIKETHROUGH
+                | cmarkn::Options::ENABLE_TASKLISTS
+                | cmarkn::Options::ENABLE_SMART_PUNCTUATION
+        }
+        let mut parser_new = cmarkn::Parser::new_ext(&dox, main_body_opts_new()).into_offset_iter();
+        while let Some((event, span)) = parser_new.next() {
+            if let cmarkn::Event::Start(cmarkn::Tag::BlockQuote(_)) = event {
+                if !dox[span.clone()].starts_with("> ") {
+                    spaceless_block_quotes.insert(span.start);
+                }
+            }
+            if let cmarkn::Event::FootnoteReference(_) = event {
+                found_footnote_references.insert(span.start + 1);
+            }
+        }
+    }
+
+    // remove cases where they don't actually differ
+    {
+        pub fn main_body_opts_old() -> cmarko::Options {
+            cmarko::Options::ENABLE_TABLES
+                | cmarko::Options::ENABLE_FOOTNOTES
+                | cmarko::Options::ENABLE_STRIKETHROUGH
+                | cmarko::Options::ENABLE_TASKLISTS
+                | cmarko::Options::ENABLE_SMART_PUNCTUATION
+        }
+        let mut parser_old = cmarko::Parser::new_ext(&dox, main_body_opts_old()).into_offset_iter();
+        while let Some((event, span)) = parser_old.next() {
+            if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event {
+                if !dox[span.clone()].starts_with("> ") {
+                    spaceless_block_quotes.remove(&span.start);
+                }
+            }
+            if let cmarko::Event::FootnoteReference(_) = event {
+                if !found_footnote_references.contains(&(span.start + 1)) {
+                    missing_footnote_references.insert(span.start + 1, span);
+                }
+            }
+        }
+    }
+
+    for start in spaceless_block_quotes {
+        let (span, precise) =
+            source_span_for_markdown_range(tcx, &dox, &(start..start + 1), &item.attrs.doc_strings)
+                .map(|span| (span, true))
+                .unwrap_or_else(|| (item.attr_span(tcx), false));
+
+        tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, span, |lint| {
+            lint.primary_message("unportable markdown");
+            lint.help(format!("confusing block quote with no space after the `>` marker"));
+            if precise {
+                lint.span_suggestion(
+                    span.shrink_to_hi(),
+                    "if the quote is intended, add a space",
+                    " ",
+                    Applicability::MaybeIncorrect,
+                );
+                lint.span_suggestion(
+                    span.shrink_to_lo(),
+                    "if it should not be a quote, escape it",
+                    "\\",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        });
+    }
+    for (_caret, span) in missing_footnote_references {
+        let (ref_span, precise) =
+            source_span_for_markdown_range(tcx, &dox, &span, &item.attrs.doc_strings)
+                .map(|span| (span, true))
+                .unwrap_or_else(|| (item.attr_span(tcx), false));
+
+        tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, ref_span, |lint| {
+            lint.primary_message("unportable markdown");
+            if precise {
+                lint.span_suggestion(
+                    ref_span.shrink_to_lo(),
+                    "if it should not be a footnote, escape it",
+                    "\\",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            if dox.as_bytes().get(span.end) == Some(&b'[') {
+                lint.help("confusing footnote reference and link");
+                if precise {
+                    lint.span_suggestion(
+                        ref_span.shrink_to_hi(),
+                        "if the footnote is intended, add a space",
+                        " ",
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    lint.help("there should be a space between the link and the footnote");
+                }
+            }
+        });
+    }
+}
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 5a5152f653959d14d68613a3a8a033fb65eec02
+Subproject c54cff0e6e4d1a0d0a2df7c1ce3d96cdd554763
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 68030493e9c..89115d4d7d6 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 30;
+pub const FORMAT_VERSION: u32 = 31;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -511,9 +511,9 @@ pub enum WherePredicate {
         /// ```
         generic_params: Vec<GenericParamDef>,
     },
-    RegionPredicate {
+    LifetimePredicate {
         lifetime: String,
-        bounds: Vec<GenericBound>,
+        outlives: Vec<String>,
     },
     EqPredicate {
         lhs: Type,
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 4ed7bee47f7dd4416b36fada1909e9a62c54624
+Subproject 154fdac39ae9629954e19e9986fd2cf2cdd8d96
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 05ea74b0d53..406f38f411e 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -103,7 +103,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<
             let args = cx.typeck_results().node_args(expr.hir_id);
 
             // If we could not resolve the method, don't apply the lint
-            let Ok(Some(resolved_method)) = Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args) else {
+            let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else {
                 return None;
             };
             if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone {
@@ -119,7 +119,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<
 
             // If we could not resolve the method, don't apply the lint
             let Ok(Some(resolved_method)) = (match kind {
-                ty::FnDef(_, args) => Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args),
+                ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args),
                 _ => Ok(None),
             }) else {
                 return None;
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 3d875e7ac2d..3e210fd153b 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -6,10 +6,10 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::Visitable;
 use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args};
 use pulldown_cmark::Event::{
-    Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
+    Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text,
 };
 use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph};
-use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
+use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd};
 use rustc_ast::ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::intravisit::{self, Visitor};
@@ -659,7 +659,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
 
     while let Some((event, range)) = events.next() {
         match event {
-            Html(tag) => {
+            Html(tag) | InlineHtml(tag) => {
                 if tag.starts_with("<code") {
                     code_level += 1;
                 } else if tag.starts_with("</code") {
@@ -670,11 +670,11 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     blockquote_level -= 1;
                 }
             },
-            Start(BlockQuote) => {
+            Start(BlockQuote(_)) => {
                 blockquote_level += 1;
                 containers.push(Container::Blockquote);
             },
-            End(BlockQuote) => {
+            End(TagEnd::BlockQuote) => {
                 blockquote_level -= 1;
                 containers.pop();
             },
@@ -699,15 +699,15 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     }
                 }
             },
-            End(CodeBlock(_)) => {
+            End(TagEnd::CodeBlock) => {
                 in_code = false;
                 is_rust = false;
                 ignore = false;
             },
-            Start(Link(_, url, _)) => in_link = Some(url),
-            End(Link(..)) => in_link = None,
-            Start(Heading(_, _, _) | Paragraph | Item) => {
-                if let Start(Heading(_, _, _)) = event {
+            Start(Link { dest_url, .. }) => in_link = Some(dest_url),
+            End(TagEnd::Link) => in_link = None,
+            Start(Heading { .. } | Paragraph | Item) => {
+                if let Start(Heading { .. }) = event {
                     in_heading = true;
                 }
                 if let Start(Item) = event {
@@ -720,11 +720,11 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 ticks_unbalanced = false;
                 paragraph_range = range;
             },
-            End(Heading(_, _, _) | Paragraph | Item) => {
-                if let End(Heading(_, _, _)) = event {
+            End(TagEnd::Heading(_) | TagEnd::Paragraph | TagEnd::Item) => {
+                if let End(TagEnd::Heading(_)) = event {
                     in_heading = false;
                 }
-                if let End(Item) = event {
+                if let End(TagEnd::Item) = event {
                     containers.pop();
                 }
                 if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) {
@@ -746,8 +746,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 text_to_check = Vec::new();
             },
             Start(FootnoteDefinition(..)) => in_footnote_definition = true,
-            End(FootnoteDefinition(..)) => in_footnote_definition = false,
-            Start(_tag) | End(_tag) => (), // We don't care about other tags
+            End(TagEnd::FootnoteDefinition) => in_footnote_definition = false,
+            Start(_) | End(_) => (), // We don't care about other tags
             SoftBreak | HardBreak => {
                 if !containers.is_empty()
                     && let Some((next_event, next_range)) = events.peek()
@@ -765,7 +765,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     );
                 }
             },
-            TaskListMarker(_) | Code(_) | Rule => (),
+            TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
             FootnoteReference(text) | Text(text) => {
                 paragraph_range.end = range.end;
                 ticks_unbalanced |= text.contains('`') && !in_code;
diff --git a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
index 745599b0e57..743ec5b9ea7 100644
--- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
     /// and it may be desirable to do so consistently for style.
     ///
     /// However, removing the brackets also introduces a public constant named after the struct,
-    /// so this is not just a syntactic simplification but an an API change, and adding them back
+    /// so this is not just a syntactic simplification but an API change, and adding them back
     /// is a *breaking* API change.
     ///
     /// ### Example
@@ -44,7 +44,7 @@ declare_clippy_lint! {
     /// and it may be desirable to do so consistently for style.
     ///
     /// However, removing the brackets also introduces a public constant named after the variant,
-    /// so this is not just a syntactic simplification but an an API change, and adding them back
+    /// so this is not just a syntactic simplification but an API change, and adding them back
     /// is a *breaking* API change.
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 42ec2c00823..d2a34c75583 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::{
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::error_reporting::traits::InferCtxtExt as _;
 
 declare_clippy_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index cb1d0de1edf..1fd8faf3ea8 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
-use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
+use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 5cb8e7bfab2..09225ac3246 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -258,7 +258,7 @@ impl<'tcx> NonCopyConst<'tcx> {
                 // e.g. implementing `has_frozen_variant` described above, and not running this function
                 // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
                 // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
-                // similar to 2., but with the a frozen variant) (e.g. borrowing
+                // similar to 2., but with a frozen variant) (e.g. borrowing
                 // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
                 // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
                 matches!(err, ErrorHandled::TooGeneric(..))
@@ -293,7 +293,7 @@ impl<'tcx> NonCopyConst<'tcx> {
         ct: ty::UnevaluatedConst<'tcx>,
         span: Span,
     ) -> EvalToValTreeResult<'tcx> {
-        match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
+        match ty::Instance::try_resolve(tcx, param_env, ct.def, ct.args) {
             Ok(Some(instance)) => {
                 let cid = GlobalId {
                     instance,
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 5e41b3f4914..6ba98a92423 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{sym, Span};
-use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
+use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
 
 declare_clippy_lint! {
     /// ### What it does
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 42b10f69c0c..f206b2ceebc 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
@@ -330,7 +330,8 @@ fn check_terminator<'tcx>(
             target: _,
             unwind: _,
             fn_span: _,
-        } => {
+        }
+        | TerminatorKind::TailCall { func, args, fn_span: _ } => {
             let fn_ty = func.ty(body, tcx);
             if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
                 if !is_const_fn(tcx, fn_def_id, msrv) {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index e5d20564196..acaeb93f44a 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -99,7 +99,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                     for (predicate, _span) in cx
                         .tcx
                         .explicit_item_super_predicates(def_id)
-                        .instantiate_identity_iter_copied()
+                        .iter_identity_copied()
                     {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
index 86667701da0..7d3c3f7c918 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
@@ -86,7 +86,6 @@ LL |     dbg!();
 help: remove the invocation before committing it to a version control system
    |
 LL -     dbg!();
-LL +     
    |
 
 error: the `dbg!` macro is intended as a debugging tool
@@ -146,7 +145,6 @@ LL |     expand_to_dbg!();
 help: remove the invocation before committing it to a version control system
    |
 LL -             dbg!();
-LL +             
    |
 
 error: the `dbg!` macro is intended as a debugging tool
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
index d21595c2fcd..16e51f4742e 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
@@ -9,7 +9,6 @@ LL |     dbg!();
 help: remove the invocation before committing it to a version control system
    |
 LL -     dbg!();
-LL +     
    |
 
 error: the `dbg!` macro is intended as a debugging tool
diff --git a/src/tools/clippy/tests/ui/manual_split_once.stderr b/src/tools/clippy/tests/ui/manual_split_once.stderr
index b4e51f473cf..c5c9be3ac63 100644
--- a/src/tools/clippy/tests/ui/manual_split_once.stderr
+++ b/src/tools/clippy/tests/ui/manual_split_once.stderr
@@ -96,12 +96,10 @@ LL |     let (l, r) = "a.b.c".split_once('.').unwrap();
 help: remove the `iter` usages
    |
 LL -     let l = iter.next().unwrap();
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let r = iter.next().unwrap();
-LL +     
    |
 
 error: manual implementation of `split_once`
@@ -121,12 +119,10 @@ LL |     let (l, r) = "a.b.c".split_once('.')?;
 help: remove the `iter` usages
    |
 LL -     let l = iter.next()?;
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let r = iter.next()?;
-LL +     
    |
 
 error: manual implementation of `rsplit_once`
@@ -146,12 +142,10 @@ LL |     let (l, r) = "a.b.c".rsplit_once('.').unwrap();
 help: remove the `iter` usages
    |
 LL -     let r = iter.next().unwrap();
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let l = iter.next().unwrap();
-LL +     
    |
 
 error: manual implementation of `rsplit_once`
@@ -171,12 +165,10 @@ LL |     let (l, r) = "a.b.c".rsplit_once('.')?;
 help: remove the `iter` usages
    |
 LL -     let r = iter.next()?;
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let l = iter.next()?;
-LL +     
    |
 
 error: manual implementation of `split_once`
@@ -202,12 +194,10 @@ LL |     let (a, b) = "a.b.c".split_once('.').unwrap();
 help: remove the `iter` usages
    |
 LL -     let a = iter.next().unwrap();
-LL +     
    |
 help: remove the `iter` usages
    |
 LL -     let b = iter.next().unwrap();
-LL +     
    |
 
 error: aborting due to 19 previous errors
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 7657ef470c5..c76f7a81843 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -98,7 +98,7 @@ fn or_fun_call() {
 
     let opt = Some(1);
     let hello = "Hello";
-    let _ = opt.ok_or(format!("{} world.", hello));
+    let _ = opt.ok_or_else(|| format!("{} world.", hello));
 
     // index
     let map = HashMap::<u64, u64>::new();
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index b5a30f29923..3070db22fc5 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -100,6 +100,12 @@ error: use of `unwrap_or` to construct default value
 LL |     let _ = stringy.unwrap_or(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
+error: use of `ok_or` followed by a function call
+  --> tests/ui/or_fun_call.rs:101:17
+   |
+LL |     let _ = opt.ok_or(format!("{} world.", hello));
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))`
+
 error: use of `unwrap_or` followed by a function call
   --> tests/ui/or_fun_call.rs:105:21
    |
@@ -190,5 +196,5 @@ error: use of `unwrap_or_else` to construct default value
 LL |         let _ = stringy.unwrap_or_else(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: aborting due to 31 previous errors
+error: aborting due to 32 previous errors
 
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
index f818a14cbe6..5fc66279f00 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
@@ -64,7 +64,6 @@ LL +         let rslt0 = mutex.lock().unwrap().abs();
 help: remove separated single usage
    |
 LL -         let rslt0 = lock.abs();
-LL +         
    |
 
 error: temporary with significant `Drop` can be early dropped
@@ -88,7 +87,6 @@ LL +         mutex.lock().unwrap().clear();
 help: remove separated single usage
    |
 LL -         lock.clear();
-LL +         
    |
 
 error: aborting due to 4 previous errors
diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml
index ebf3082fb4f..882d3d63525 100644
--- a/src/tools/generate-windows-sys/Cargo.toml
+++ b/src/tools/generate-windows-sys/Cargo.toml
@@ -4,4 +4,4 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies.windows-bindgen]
-version = "0.57.0"
+version = "0.58.0"
diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs
index c8913910bd6..fd21e7a86b0 100644
--- a/src/tools/generate-windows-sys/src/main.rs
+++ b/src/tools/generate-windows-sys/src/main.rs
@@ -17,6 +17,7 @@ fn main() -> Result<(), Box<dyn Error>> {
 
     let mut f = std::fs::File::options().append(true).open("windows_sys.rs")?;
     writeln!(&mut f, "// ignore-tidy-filelength")?;
+    writeln!(&mut f, "use super::windows_targets;")?;
 
     Ok(())
 }
diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs
index 50697d46b8c..5f72bd171a1 100644
--- a/src/tools/jsondocck/src/cache.rs
+++ b/src/tools/jsondocck/src/cache.rs
@@ -23,7 +23,7 @@ impl Cache {
 
         Cache {
             value: serde_json::from_str::<Value>(&content).expect("failed to convert from JSON"),
-            variables: HashMap::new(),
+            variables: HashMap::from([("FILE".to_owned(), config.template.clone().into())]),
         }
     }
 
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index 688b403bf0e..429c6151796 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -56,6 +56,8 @@ pub enum CommandKind {
 
 impl CommandKind {
     fn validate(&self, args: &[String], lineno: usize) -> bool {
+        // FIXME(adotinthevoid): We should "parse, don't validate" here, so we avoid ad-hoc
+        // indexing in check_command.
         let count = match self {
             CommandKind::Has => (1..=2).contains(&args.len()),
             CommandKind::IsMany => args.len() >= 2,
@@ -71,7 +73,7 @@ impl CommandKind {
         if let CommandKind::Count = self {
             if args[1].parse::<usize>().is_err() {
                 print_err(
-                    &format!("Second argument to @count must be a valid usize (got `{}`)", args[2]),
+                    &format!("Second argument to @count must be a valid usize (got `{}`)", args[1]),
                     lineno,
                 );
                 return false;
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index 1713a4d812c..cd011dce784 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -374,8 +374,8 @@ impl<'a> Validator<'a> {
                 bounds.iter().for_each(|b| self.check_generic_bound(b));
                 generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
             }
-            WherePredicate::RegionPredicate { lifetime: _, bounds } => {
-                bounds.iter().for_each(|b| self.check_generic_bound(b));
+            WherePredicate::LifetimePredicate { lifetime: _, outlives: _ } => {
+                // nop, all strings.
             }
             WherePredicate::EqPredicate { lhs, rhs } => {
                 self.check_type(lhs);
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 7321bd1bb52..72ae3ed26e8 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -59,6 +59,8 @@ const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[
     // This is being used in the sense of 'inclusive range', not a markdown link
     ("core/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
     ("std/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
+    ("core/range/legacy/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
+    ("std/range/legacy/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
     ("core/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
     ("alloc/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
     ("std/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index fd59ad3b8f1..5a35166769e 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-9ed2ab3790ff41bf741dd690befd6a1c1e2b23ca
+66b4f0021bfb11a8c20d084c99a40f4a78ce1d38
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index 8abc8530f7c..a753de28a04 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -19,7 +19,7 @@ pub enum AccessCause {
     Explicit(AccessKind),
     Reborrow,
     Dealloc,
-    FnExit,
+    FnExit(AccessKind),
 }
 
 impl fmt::Display for AccessCause {
@@ -28,7 +28,11 @@ impl fmt::Display for AccessCause {
             Self::Explicit(kind) => write!(f, "{kind}"),
             Self::Reborrow => write!(f, "reborrow"),
             Self::Dealloc => write!(f, "deallocation"),
-            Self::FnExit => write!(f, "protector release"),
+            // This is dead code, since the protector release access itself can never
+            // cause UB (while the protector is active, if some other access invalidates
+            // further use of the protected tag, that is immediate UB).
+            // Describing the cause of UB is the only time this function is called.
+            Self::FnExit(_) => unreachable!("protector accesses can never be the source of UB"),
         }
     }
 }
@@ -40,7 +44,7 @@ impl AccessCause {
             Self::Explicit(kind) => format!("{rel} {kind}"),
             Self::Reborrow => format!("reborrow (acting as a {rel} read access)"),
             Self::Dealloc => format!("deallocation (acting as a {rel} write access)"),
-            Self::FnExit => format!("protector release (acting as a {rel} read access)"),
+            Self::FnExit(kind) => format!("protector release (acting as a {rel} {kind})"),
         }
     }
 }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 77e003ab8a7..86074384084 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -68,13 +68,11 @@ impl<'tcx> Tree {
         let global = machine.borrow_tracker.as_ref().unwrap();
         let span = machine.current_span();
         self.perform_access(
-            access_kind,
             tag,
-            Some(range),
+            Some((range, access_kind, diagnostics::AccessCause::Explicit(access_kind))),
             global,
             alloc_id,
             span,
-            diagnostics::AccessCause::Explicit(access_kind),
         )
     }
 
@@ -115,15 +113,8 @@ impl<'tcx> Tree {
         alloc_id: AllocId, // diagnostics
     ) -> InterpResult<'tcx> {
         let span = machine.current_span();
-        self.perform_access(
-            AccessKind::Read,
-            tag,
-            None, // no specified range because it occurs on the entire allocation
-            global,
-            alloc_id,
-            span,
-            diagnostics::AccessCause::FnExit,
-        )
+        // `None` makes it the magic on-protector-end operation
+        self.perform_access(tag, None, global, alloc_id, span)
     }
 }
 
@@ -297,13 +288,11 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // All reborrows incur a (possibly zero-sized) read access to the parent
         tree_borrows.perform_access(
-            AccessKind::Read,
             orig_tag,
-            Some(range),
+            Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)),
             this.machine.borrow_tracker.as_ref().unwrap(),
             alloc_id,
             this.machine.current_span(),
-            diagnostics::AccessCause::Reborrow,
         )?;
         // Record the parent-child pair in the tree.
         tree_borrows.new_child(orig_tag, new_tag, new_perm.initial_state, range, span)?;
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 fb3a4c8dad9..7aa9c3e862b 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -186,6 +186,10 @@ impl Permission {
     pub fn is_disabled(&self) -> bool {
         self.inner == Disabled
     }
+    /// Check if `self` is the post-child-write state of a pointer (is `Active`).
+    pub fn is_active(&self) -> bool {
+        self.inner == Active
+    }
 
     /// Default initial permission of the root of a new tree at inbounds positions.
     /// Must *only* be used for the root, this is not in general an "initial" permission!
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 ff4589657af..90bd1103218 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -530,13 +530,11 @@ impl<'tcx> Tree {
         span: Span,        // diagnostics
     ) -> InterpResult<'tcx> {
         self.perform_access(
-            AccessKind::Write,
             tag,
-            Some(access_range),
+            Some((access_range, AccessKind::Write, diagnostics::AccessCause::Dealloc)),
             global,
             alloc_id,
             span,
-            diagnostics::AccessCause::Dealloc,
         )?;
         for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size) {
             TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
@@ -570,12 +568,16 @@ impl<'tcx> Tree {
     }
 
     /// Map the per-node and per-location `LocationState::perform_access`
-    /// to each location of `access_range`, on every tag of the allocation.
+    /// to each location of the first component of `access_range_and_kind`,
+    /// on every tag of the allocation.
     ///
-    /// If `access_range` is `None`, this is interpreted as the special
+    /// If `access_range_and_kind` is `None`, this is interpreted as the special
     /// access that is applied on protector release:
     /// - the access will be applied only to initialized locations of the allocation,
-    /// - and it will not be visible to children.
+    /// - it will not be visible to children,
+    /// - it will be recorded as a `FnExit` diagnostic access
+    /// - and it will be a read except if the location is `Active`, i.e. has been written to,
+    ///   in which case it will be a write.
     ///
     /// `LocationState::perform_access` will take care of raising transition
     /// errors and updating the `initialized` status of each location,
@@ -585,13 +587,11 @@ impl<'tcx> Tree {
     /// - recording the history.
     pub fn perform_access(
         &mut self,
-        access_kind: AccessKind,
         tag: BorTag,
-        access_range: Option<AllocRange>,
+        access_range_and_kind: Option<(AllocRange, AccessKind, diagnostics::AccessCause)>,
         global: &GlobalState,
-        alloc_id: AllocId,                      // diagnostics
-        span: Span,                             // diagnostics
-        access_cause: diagnostics::AccessCause, // diagnostics
+        alloc_id: AllocId, // diagnostics
+        span: Span,        // diagnostics
     ) -> InterpResult<'tcx> {
         use std::ops::Range;
         // Performs the per-node work:
@@ -605,6 +605,8 @@ impl<'tcx> Tree {
         // `perms_range` is only for diagnostics (it is the range of
         // the `RangeMap` on which we are currently working).
         let node_app = |perms_range: Range<u64>,
+                        access_kind: AccessKind,
+                        access_cause: diagnostics::AccessCause,
                         args: NodeAppArgs<'_>|
          -> Result<ContinueTraversal, TransitionError> {
             let NodeAppArgs { node, mut perm, rel_pos } = args;
@@ -618,14 +620,13 @@ impl<'tcx> Tree {
 
             let protected = global.borrow().protected_tags.contains_key(&node.tag);
             let transition = old_state.perform_access(access_kind, rel_pos, protected)?;
-
             // Record the event as part of the history
             if !transition.is_noop() {
                 node.debug_info.history.push(diagnostics::Event {
                     transition,
                     is_foreign: rel_pos.is_foreign(),
                     access_cause,
-                    access_range,
+                    access_range: access_range_and_kind.map(|x| x.0),
                     transition_range: perms_range,
                     span,
                 });
@@ -636,6 +637,7 @@ impl<'tcx> Tree {
         // Error handler in case `node_app` goes wrong.
         // Wraps the faulty transition in more context for diagnostics.
         let err_handler = |perms_range: Range<u64>,
+                           access_cause: diagnostics::AccessCause,
                            args: ErrHandlerArgs<'_, TransitionError>|
          -> InterpError<'tcx> {
             let ErrHandlerArgs { error_kind, conflicting_info, accessed_info } = args;
@@ -650,7 +652,7 @@ impl<'tcx> Tree {
             .build()
         };
 
-        if let Some(access_range) = access_range {
+        if let Some((access_range, access_kind, access_cause)) = access_range_and_kind {
             // Default branch: this is a "normal" access through a known range.
             // We iterate over affected locations and traverse the tree for each of them.
             for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size)
@@ -658,8 +660,8 @@ impl<'tcx> Tree {
                 TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
                     .traverse_parents_this_children_others(
                         tag,
-                        |args| node_app(perms_range.clone(), args),
-                        |args| err_handler(perms_range.clone(), args),
+                        |args| node_app(perms_range.clone(), access_kind, access_cause, args),
+                        |args| err_handler(perms_range.clone(), access_cause, args),
                     )?;
             }
         } else {
@@ -678,11 +680,14 @@ impl<'tcx> Tree {
                 if let Some(p) = perms.get(idx)
                     && p.initialized
                 {
+                    let access_kind =
+                        if p.permission.is_active() { AccessKind::Write } else { AccessKind::Read };
+                    let access_cause = diagnostics::AccessCause::FnExit(access_kind);
                     TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
                         .traverse_nonchildren(
                         tag,
-                        |args| node_app(perms_range.clone(), args),
-                        |args| err_handler(perms_range.clone(), args),
+                        |args| node_app(perms_range.clone(), access_kind, access_cause, args),
+                        |args| err_handler(perms_range.clone(), access_cause, args),
                     )?;
                 }
             }
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index c0827cce263..9142b8b5fdb 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -375,7 +375,7 @@ pub fn create_ecx<'tcx>(
             });
             let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
             let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
-            let start_instance = ty::Instance::resolve(
+            let start_instance = ty::Instance::try_resolve(
                 tcx,
                 ty::ParamEnv::reveal_all(),
                 start_id,
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index a7a6f8cfd87..590e8984e99 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -24,7 +24,7 @@ use rustc_middle::ty::{
     FloatTy, IntTy, Ty, TyCtxt, UintTy,
 };
 use rustc_session::config::CrateType;
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{Span, Symbol};
 use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
 use rustc_target::spec::abi::Abi;
 
@@ -1182,14 +1182,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         this.alloc_mark_immutable(provenance.get_alloc_id().unwrap()).unwrap();
     }
 
-    fn item_link_name(&self, def_id: DefId) -> Symbol {
-        let tcx = self.eval_context_ref().tcx;
-        match tcx.get_attrs(def_id, sym::link_name).filter_map(|a| a.value_str()).next() {
-            Some(name) => name,
-            None => tcx.item_name(def_id),
-        }
-    }
-
     /// Converts `src` from floating point to integer type `dest_ty`
     /// after rounding with mode `round`.
     /// Returns `None` if `f` is NaN or out of range.
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 0d91279f9f4..714d97823f4 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -954,7 +954,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             // foreign function
             // Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
             let args = ecx.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
-            let link_name = ecx.item_link_name(instance.def_id());
+            let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name);
             return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
         }
 
@@ -1050,7 +1050,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx: &MiriInterpCx<'tcx>,
         def_id: DefId,
     ) -> InterpResult<'tcx, StrictPointer> {
-        let link_name = ecx.item_link_name(def_id);
+        let link_name = Symbol::intern(ecx.tcx.symbol_name(Instance::mono(*ecx.tcx, def_id)).name);
         if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) {
             // Various parts of the engine rely on `get_alloc_info` for size and alignment
             // information. That uses the type information of this static.
@@ -1434,7 +1434,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx: &mut InterpCx<'tcx, Self>,
         frame: Frame<'tcx, Provenance, FrameExtra<'tcx>>,
         unwinding: bool,
-    ) -> InterpResult<'tcx, StackPopJump> {
+    ) -> InterpResult<'tcx, ReturnAction> {
         if frame.extra.is_user_relevant {
             // All that we store is whether or not the frame we just removed is local, so now we
             // have no idea where the next topmost local frame is. So we recompute it.
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 06be9c1e63e..24a4b5f26a9 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -119,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?;
 
         // This has to be an actual global fn ptr, not a dlsym function.
-        let fn_instance = if let Some(GlobalAlloc::Function(instance)) =
+        let fn_instance = if let Some(GlobalAlloc::Function { instance, .. }) =
             this.tcx.try_get_global_alloc(alloc_id)
         {
             instance
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index f9ccc6ad4d2..9004f7efc8b 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -46,24 +46,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
         let this = self.eval_context_mut();
-        let tcx = this.tcx.tcx;
 
         // Some shims forward to other MIR bodies.
         match link_name.as_str() {
-            // This matches calls to the foreign item `panic_impl`.
-            // The implementation is provided by the function with the `#[panic_handler]` attribute.
-            "panic_impl" => {
-                // We don't use `check_shim` here because we are just forwarding to the lang
-                // item. Argument count checking will be performed when the returned `Body` is
-                // called.
-                this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?;
-                let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
-                let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
-                return Ok(Some((
-                    this.load_mir(panic_impl_instance.def, None)?,
-                    panic_impl_instance,
-                )));
-            }
             "__rust_alloc_error_handler" => {
                 // Forward to the right symbol that implements this function.
                 let Some(handler_kind) = this.tcx.alloc_error_handler_kind(()) else {
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index ef832f5bbbd..306dce5edcd 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -113,7 +113,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         mut extra: FrameExtra<'tcx>,
         unwinding: bool,
-    ) -> InterpResult<'tcx, StackPopJump> {
+    ) -> InterpResult<'tcx, ReturnAction> {
         let this = self.eval_context_mut();
         trace!("handle_stack_pop_unwind(extra = {:?}, unwinding = {})", extra, unwinding);
 
@@ -150,9 +150,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             )?;
 
             // We pushed a new stack frame, the engine should not do any jumping now!
-            Ok(StackPopJump::NoJump)
+            Ok(ReturnAction::NoJump)
         } else {
-            Ok(StackPopJump::Normal)
+            Ok(ReturnAction::Normal)
         }
     }
 
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 599f78e712a..7f6a0978103 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -273,6 +273,32 @@ impl FdTable {
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
+    fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_mut();
+
+        let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
+            return this.fd_not_found();
+        };
+        Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0))
+    }
+
+    fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_mut();
+
+        let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
+            return this.fd_not_found();
+        };
+        if new_fd != old_fd {
+            // Close new_fd if it is previously opened.
+            // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive.
+            if let Some(file_descriptor) = this.machine.fds.fds.insert(new_fd, dup_fd) {
+                // Ignore close error (not interpreter's) according to dup2() doc.
+                file_descriptor.close(this.machine.communicate())?.ok();
+            }
+        }
+        Ok(new_fd)
+    }
+
     fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
         let this = self.eval_context_mut();
 
@@ -334,14 +360,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let fd = this.read_scalar(fd_op)?.to_i32()?;
 
-        Ok(Scalar::from_i32(if let Some(file_descriptor) = this.machine.fds.remove(fd) {
-            let result = file_descriptor.close(this.machine.communicate())?;
-            // return `0` if close is successful
-            let result = result.map(|()| 0i32);
-            this.try_unwrap_io_result(result)?
-        } else {
-            this.fd_not_found()?
-        }))
+        let Some(file_descriptor) = this.machine.fds.remove(fd) else {
+            return Ok(Scalar::from_i32(this.fd_not_found()?));
+        };
+        let result = file_descriptor.close(this.machine.communicate())?;
+        // return `0` if close is successful
+        let result = result.map(|()| 0i32);
+        Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
     /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 53ad40cfd2c..2421f9244f3 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -115,6 +115,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result = this.fcntl(args)?;
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
+            "dup" => {
+                let [old_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let old_fd = this.read_scalar(old_fd)?.to_i32()?;
+                let new_fd = this.dup(old_fd)?;
+                this.write_scalar(Scalar::from_i32(new_fd), dest)?;
+            }
+            "dup2" => {
+                let [old_fd, new_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let old_fd = this.read_scalar(old_fd)?.to_i32()?;
+                let new_fd = this.read_scalar(new_fd)?.to_i32()?;
+                let result = this.dup2(old_fd, new_fd)?;
+                this.write_scalar(Scalar::from_i32(result), dest)?;
+            }
 
             // File and file system access
             "open" | "open64" => {
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index c9db798caad..71f6a2bc033 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -758,6 +758,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
 
+            "_Unwind_RaiseException" => {
+                // This is not formally part of POSIX, but it is very wide-spread on POSIX systems.
+                // It was originally specified as part of the Itanium C++ ABI:
+                // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw.
+                // MinGW implements _Unwind_RaiseException on top of SEH exceptions.
+                if this.tcx.sess.target.env != "gnu" {
+                    throw_unsup_format!(
+                        "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
+                    );
+                }
+                // This function looks and behaves excatly like miri_start_unwind.
+                let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?;
+                this.handle_miri_start_unwind(payload)?;
+                return Ok(EmulateItemResult::NeedsUnwind);
+            }
+
             _ => return Ok(EmulateItemResult::NotSupported),
         }
 
diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs
index 0d2977b7b6f..f36bb4826e4 100644
--- a/src/tools/miri/src/shims/x86/avx.rs
+++ b/src/tools/miri/src/shims/x86/avx.rs
@@ -338,6 +338,17 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
                 this.write_scalar(Scalar::from_i32(res.into()), dest)?;
             }
+            // Used to implement the `_mm256_zeroupper` and `_mm256_zeroall` functions.
+            // These function clear out the upper 128 bits of all avx registers or
+            // zero out all avx registers respectively.
+            "vzeroupper" | "vzeroall" => {
+                // These functions are purely a performance hint for the CPU.
+                // Any registers currently in use will be saved beforehand by the
+                // compiler, making these functions no-ops.
+
+                // The only thing that needs to be ensured is the correct calling convention.
+                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+            }
             _ => return Ok(EmulateItemResult::NotSupported),
         }
         Ok(EmulateItemResult::NeedsReturn)
diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs
new file mode 100644
index 00000000000..5f00dbf2573
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs
@@ -0,0 +1,10 @@
+//@error-in-other-file: Undefined Behavior: calling a function with calling convention C using calling convention Rust
+#![feature(explicit_tail_calls)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let f = unsafe { std::mem::transmute::<extern "C" fn(), fn()>(f) };
+    become f();
+}
+
+extern "C" fn f() {}
diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
new file mode 100644
index 00000000000..b157e9f0b21
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
@@ -0,0 +1,25 @@
+error: Undefined Behavior: calling a function with calling convention C using calling convention Rust
+  --> RUSTLIB/core/src/ops/function.rs:LL:CC
+   |
+LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention C using calling convention Rust
+   |
+   = 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 `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at RUSTLIB/core/src/ops/function.rs:LL:CC
+   = note: inside `std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
+   = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC
+   = note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at RUSTLIB/core/src/ops/function.rs:LL:CC
+   = note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panic.rs:LL:CC
+   = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC
+   = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::r#try::<isize, {closure@std::rt::lang_start_internal::{closure#2}}>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC
+   = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC
+   = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs
new file mode 100644
index 00000000000..6df132d3255
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs
@@ -0,0 +1,17 @@
+#![feature(explicit_tail_calls)]
+#![allow(incomplete_features)]
+
+fn main() {
+    // FIXME(explicit_tail_calls):
+    //   the error should point to `become g(x)`,
+    //   but tail calls mess up the backtrace it seems like...
+    f(0);
+    //~^ error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32
+}
+
+fn f(x: u32) {
+    let g = unsafe { std::mem::transmute::<fn(i32), fn(u32)>(g) };
+    become g(x);
+}
+
+fn g(_: i32) {}
diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr
new file mode 100644
index 00000000000..8823ab9b970
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr
@@ -0,0 +1,17 @@
+error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32
+  --> $DIR/signature-mismatch-arg.rs:LL:CC
+   |
+LL |     f(0);
+   |     ^^^^ calling a function with argument of type i32 passing data of type u32
+   |
+   = 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
+   = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
+   = help: if you think this code should be accepted anyway, please report an issue with Miri
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/signature-mismatch-arg.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/tree_borrows/protector-write-lazy.rs b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs
new file mode 100644
index 00000000000..238f6dba9d3
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.rs
@@ -0,0 +1,35 @@
+//@compile-flags: -Zmiri-tree-borrows
+// This test tests that TB's protector end semantics correctly ensure
+// that protected activated writes can be reordered.
+fn the_other_function(ref_to_fst_elem: &mut i32, ptr_to_vec: *mut i32) -> *mut i32 {
+    // Activate the reference. Afterwards, we should be able to reorder arbitrary writes.
+    *ref_to_fst_elem = 0;
+    // Here is such an arbitrary write.
+    // It could be moved down after the retag, in which case the `funky_ref` would be invalidated.
+    // We need to ensure that the `funky_ptr` is unusable even if the write to `ref_to_fst_elem`
+    // happens before the retag.
+    *ref_to_fst_elem = 42;
+    // this creates a reference that is Reserved Lazy on the first element (offset 0).
+    // It does so by doing a proper retag on the second element (offset 1), which is fine
+    // since nothing else happens at that offset, but the lazy init mechanism means it's
+    // also reserved at offset 0, but not initialized.
+    let funky_ptr_lazy_on_fst_elem =
+        unsafe { (&mut *(ptr_to_vec.wrapping_add(1))) as *mut i32 }.wrapping_sub(1);
+    // If we write to `ref_to_fst_elem` here, then any further access to `funky_ptr_lazy_on_fst_elem` would
+    // definitely be UB. Since the compiler ought to be able to reorder the write of `42` above down to
+    // here, that means we want this program to also be UB.
+    return funky_ptr_lazy_on_fst_elem;
+}
+
+fn main() {
+    let mut v = vec![0, 1];
+    // get a pointer to the root of the allocation
+    // note that it's not important it's the actual root, what matters is that it's a parent
+    // of both references that will be created
+    let ptr_to_vec = v.as_mut_ptr();
+    let ref_to_fst_elem = unsafe { &mut *ptr_to_vec };
+    let funky_ptr_lazy_on_fst_elem = the_other_function(ref_to_fst_elem, ptr_to_vec);
+    // now we try to use the funky lazy pointer.
+    // It should be UB, since the write-on-protector-end should disable it.
+    unsafe { println!("Value of funky: {}", *funky_ptr_lazy_on_fst_elem) } //~ ERROR: /reborrow through .* is forbidden/
+}
diff --git a/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr
new file mode 100644
index 00000000000..955abd144c7
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr
@@ -0,0 +1,27 @@
+error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden
+  --> $DIR/protector-write-lazy.rs:LL:CC
+   |
+LL |     unsafe { println!("Value of funky: {}", *funky_ptr_lazy_on_fst_elem) }
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow through <TAG> at ALLOC[0x0] is forbidden
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
+help: the accessed tag <TAG> was created here, in the initial state Reserved
+  --> $DIR/protector-write-lazy.rs:LL:CC
+   |
+LL |         unsafe { (&mut *(ptr_to_vec.wrapping_add(1))) as *mut i32 }.wrapping_sub(1);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: the accessed tag <TAG> later transitioned to Disabled due to a protector release (acting as a foreign write access) on every location previously accessed by this tag
+  --> $DIR/protector-write-lazy.rs:LL:CC
+   |
+LL | }
+   |  ^
+   = help: this transition corresponds to a loss of read and write permissions
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at $DIR/protector-write-lazy.rs:LL:CC
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+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/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
index 80c9757e9c9..da685e5c6b7 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -15,6 +15,7 @@ use std::path::PathBuf;
 mod utils;
 
 fn main() {
+    test_dup();
     test_dup_stdout_stderr();
     test_canonicalize_too_long();
     test_rename();
@@ -74,6 +75,31 @@ fn test_dup_stdout_stderr() {
     }
 }
 
+fn test_dup() {
+    let bytes = b"dup and dup2";
+    let path = utils::prepare_with_content("miri_test_libc_dup.txt", bytes);
+
+    let mut name = path.into_os_string();
+    name.push("\0");
+    let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>();
+    unsafe {
+        let fd = libc::open(name_ptr, libc::O_RDONLY);
+        let mut first_buf = [0u8; 4];
+        libc::read(fd, first_buf.as_mut_ptr() as *mut libc::c_void, 4);
+        assert_eq!(&first_buf, b"dup ");
+
+        let new_fd = libc::dup(fd);
+        let mut second_buf = [0u8; 4];
+        libc::read(new_fd, second_buf.as_mut_ptr() as *mut libc::c_void, 4);
+        assert_eq!(&second_buf, b"and ");
+
+        let new_fd2 = libc::dup2(fd, 8);
+        let mut third_buf = [0u8; 4];
+        libc::read(new_fd2, third_buf.as_mut_ptr() as *mut libc::c_void, 4);
+        assert_eq!(&third_buf, b"dup2");
+    }
+}
+
 fn test_canonicalize_too_long() {
     // Make sure we get an error for long paths.
     let too_long = "x/".repeat(libc::PATH_MAX.try_into().unwrap());
diff --git a/src/tools/miri/tests/pass/async-closure.rs b/src/tools/miri/tests/pass/async-closure.rs
index 2f7ec2b9e6f..721af578883 100644
--- a/src/tools/miri/tests/pass/async-closure.rs
+++ b/src/tools/miri/tests/pass/async-closure.rs
@@ -1,7 +1,8 @@
 #![feature(async_closure, noop_waker, async_fn_traits)]
+#![allow(unused)]
 
 use std::future::Future;
-use std::ops::{AsyncFnMut, AsyncFnOnce};
+use std::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
 use std::pin::pin;
 use std::task::*;
 
@@ -17,6 +18,10 @@ pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
     }
 }
 
+async fn call(f: &mut impl AsyncFn(i32)) {
+    f(0).await;
+}
+
 async fn call_mut(f: &mut impl AsyncFnMut(i32)) {
     f(0).await;
 }
@@ -26,10 +31,10 @@ async fn call_once(f: impl AsyncFnOnce(i32)) {
 }
 
 async fn call_normal<F: Future<Output = ()>>(f: &impl Fn(i32) -> F) {
-    f(0).await;
+    f(1).await;
 }
 
-async fn call_normal_once<F: Future<Output = ()>>(f: impl FnOnce(i32) -> F) {
+async fn call_normal_mut<F: Future<Output = ()>>(f: &mut impl FnMut(i32) -> F) {
     f(1).await;
 }
 
@@ -39,14 +44,16 @@ pub fn main() {
         let mut async_closure = async move |a: i32| {
             println!("{a} {b}");
         };
+        call(&mut async_closure).await;
         call_mut(&mut async_closure).await;
         call_once(async_closure).await;
 
-        // No-capture closures implement `Fn`.
-        let async_closure = async move |a: i32| {
-            println!("{a}");
+        let b = 2i32;
+        let mut async_closure = async |a: i32| {
+            println!("{a} {b}");
         };
         call_normal(&async_closure).await;
-        call_normal_once(async_closure).await;
+        call_normal_mut(&mut async_closure).await;
+        call_once(async_closure).await;
     });
 }
diff --git a/src/tools/miri/tests/pass/async-closure.stdout b/src/tools/miri/tests/pass/async-closure.stdout
index 7baae1aa94f..217944c84a2 100644
--- a/src/tools/miri/tests/pass/async-closure.stdout
+++ b/src/tools/miri/tests/pass/async-closure.stdout
@@ -1,4 +1,6 @@
 0 2
+0 2
+1 2
+1 2
+1 2
 1 2
-0
-1
diff --git a/src/tools/miri/tests/pass/function_pointers.rs b/src/tools/miri/tests/pass/function_pointers.rs
index 36679b7180a..2aa3ebf2dd0 100644
--- a/src/tools/miri/tests/pass/function_pointers.rs
+++ b/src/tools/miri/tests/pass/function_pointers.rs
@@ -23,6 +23,7 @@ fn h(i: i32, j: i32) -> i32 {
     j * i * 7
 }
 
+#[inline(never)]
 fn i() -> i32 {
     73
 }
@@ -77,7 +78,7 @@ fn main() {
     assert_eq!(indirect_mut3(h), 210);
     assert_eq!(indirect_once3(h), 210);
     // Check that `i` always has the same address. This is not guaranteed
-    // but Miri currently uses a fixed address for monomorphic functions.
+    // but Miri currently uses a fixed address for non-inlineable monomorphic functions.
     assert!(return_fn_ptr(i) == i);
     assert!(return_fn_ptr(i) as unsafe fn() -> i32 == i as fn() -> i32 as unsafe fn() -> i32);
     // Miri gives different addresses to different reifications of a generic function.
diff --git a/src/tools/miri/tests/pass/intptrcast.rs b/src/tools/miri/tests/pass/intptrcast.rs
index 4e9fa12c181..fb1a1dfae5d 100644
--- a/src/tools/miri/tests/pass/intptrcast.rs
+++ b/src/tools/miri/tests/pass/intptrcast.rs
@@ -35,7 +35,7 @@ fn cast_dangling() {
 fn format() {
     // Pointer string formatting! We can't check the output as it changes when libstd changes,
     // but we can make sure Miri does not error.
-    format!("{:?}", &mut 13 as *mut _);
+    let _ = format!("{:?}", &mut 13 as *mut _);
 }
 
 fn transmute() {
@@ -52,7 +52,7 @@ fn ptr_bitops1() {
     let one = bytes.as_ptr().wrapping_offset(1);
     let three = bytes.as_ptr().wrapping_offset(3);
     let res = (one as usize) | (three as usize);
-    format!("{}", res);
+    let _ = format!("{}", res);
 }
 
 fn ptr_bitops2() {
diff --git a/src/tools/miri/tests/pass/issues/issue-91636.rs b/src/tools/miri/tests/pass/issues/issue-91636.rs
index 21000bb68d2..00370165812 100644
--- a/src/tools/miri/tests/pass/issues/issue-91636.rs
+++ b/src/tools/miri/tests/pass/issues/issue-91636.rs
@@ -10,6 +10,7 @@ impl Function {
     }
 }
 
+#[inline(never)]
 fn dummy(_: &str) {}
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/packed_struct.rs b/src/tools/miri/tests/pass/packed_struct.rs
index b86235e0c67..039eb5adef0 100644
--- a/src/tools/miri/tests/pass/packed_struct.rs
+++ b/src/tools/miri/tests/pass/packed_struct.rs
@@ -138,7 +138,7 @@ fn test_derive() {
     assert_eq!(x.partial_cmp(&y).unwrap(), x.cmp(&y));
     x.hash(&mut DefaultHasher::new());
     P::default();
-    format!("{:?}", x);
+    let _ = format!("{:?}", x);
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 35980fad15d..16d3e8cab30 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -202,7 +202,7 @@ fn test_errors() {
     // Opening a non-existing file should fail with a "not found" error.
     assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
     // Make sure we can also format this.
-    format!("{0}: {0:?}", File::open(&path).unwrap_err());
+    let _ = format!("{0}: {0:?}", File::open(&path).unwrap_err());
     // Removing a non-existing file should fail with a "not found" error.
     assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
     // Reading the metadata of a non-existing file should fail with a "not found" error.
@@ -301,5 +301,5 @@ fn test_from_raw_os_error() {
     let error = Error::from_raw_os_error(code);
     assert!(matches!(error.kind(), ErrorKind::Uncategorized));
     // Make sure we can also format this.
-    format!("{error:?}");
+    let _ = format!("{error:?}");
 }
diff --git a/src/tools/miri/tests/pass/shims/io.rs b/src/tools/miri/tests/pass/shims/io.rs
index d20fc75b793..420ef95a0cb 100644
--- a/src/tools/miri/tests/pass/shims/io.rs
+++ b/src/tools/miri/tests/pass/shims/io.rs
@@ -15,5 +15,5 @@ fn main() {
         panic!("unsupported OS")
     };
     let err = io::Error::from_raw_os_error(raw_os_error);
-    format!("{err}: {err:?}");
+    let _ = format!("{err}: {err:?}");
 }
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
index 7d43cc596ae..728f57d48f1 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
@@ -1342,6 +1342,11 @@ unsafe fn test_avx() {
         assert_eq!(r, 1);
     }
     test_mm_testnzc_ps();
+
+    // These intrinsics are functionally no-ops. The only thing
+    // that needs to be tested is that they can be executed.
+    _mm256_zeroupper();
+    _mm256_zeroall();
 }
 
 #[target_feature(enable = "sse2")]
diff --git a/src/tools/miri/tests/pass/tail_call.rs b/src/tools/miri/tests/pass/tail_call.rs
new file mode 100644
index 00000000000..f6200706398
--- /dev/null
+++ b/src/tools/miri/tests/pass/tail_call.rs
@@ -0,0 +1,39 @@
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+fn main() {
+    assert_eq!(factorial(10), 3_628_800);
+    assert_eq!(mutually_recursive_identity(1000), 1000);
+}
+
+fn factorial(n: u32) -> u32 {
+    fn factorial_acc(n: u32, acc: u32) -> u32 {
+        match n {
+            0 => acc,
+            _ => become factorial_acc(n - 1, acc * n),
+        }
+    }
+
+    factorial_acc(n, 1)
+}
+
+// this is of course very silly, but we need to demonstrate mutual recursion somehow so...
+fn mutually_recursive_identity(x: u32) -> u32 {
+    fn switch(src: u32, tgt: u32) -> u32 {
+        match src {
+            0 => tgt,
+            _ if src % 7 == 0 => become advance_with_extra_steps(src, tgt),
+            _ => become advance(src, tgt),
+        }
+    }
+
+    fn advance(src: u32, tgt: u32) -> u32 {
+        become switch(src - 1, tgt + 1)
+    }
+
+    fn advance_with_extra_steps(src: u32, tgt: u32) -> u32 {
+        become advance(src, tgt)
+    }
+
+    switch(x, 0)
+}
diff --git a/src/tools/miri/tests/pass/vecdeque.rs b/src/tools/miri/tests/pass/vecdeque.rs
index 77c4ca5a04e..9153c428e18 100644
--- a/src/tools/miri/tests/pass/vecdeque.rs
+++ b/src/tools/miri/tests/pass/vecdeque.rs
@@ -31,8 +31,8 @@ fn main() {
     }
 
     // Regression test for Debug impl's
-    format!("{:?} {:?}", dst, dst.iter());
-    format!("{:?}", VecDeque::<u32>::new().iter());
+    let _ = format!("{:?} {:?}", dst, dst.iter());
+    let _ = format!("{:?}", VecDeque::<u32>::new().iter());
 
     for a in dst {
         assert_eq!(*a, 2);
diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs
index dd2c09c430b..42de3caf547 100644
--- a/src/tools/remote-test-client/src/main.rs
+++ b/src/tools/remote-test-client/src/main.rs
@@ -71,7 +71,7 @@ fn spawn_emulator(target: &str, server: &Path, tmpdir: &Path, rootfs: Option<Pat
 
     // Wait for the emulator to come online
     loop {
-        let dur = Duration::from_millis(100);
+        let dur = Duration::from_millis(2000);
         if let Ok(mut client) = TcpStream::connect(&device_address) {
             t!(client.set_read_timeout(Some(dur)));
             t!(client.set_write_timeout(Some(dur)));
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 0a1bd9b0b34..c506c3d6b61 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -75,11 +75,12 @@ impl Command {
     /// Generic command arguments provider. Prefer specific helper methods if possible.
     /// Note that for some executables, arguments might be platform specific. For C/C++
     /// compilers, arguments might be platform *and* compiler specific.
-    pub fn args<S>(&mut self, args: &[S]) -> &mut Self
+    pub fn args<S, V>(&mut self, args: V) -> &mut Self
     where
         S: AsRef<ffi::OsStr>,
+        V: AsRef<[S]>,
     {
-        self.cmd.args(args);
+        self.cmd.args(args.as_ref());
         self
     }
 
@@ -185,14 +186,14 @@ impl CompletedProcess {
     /// Checks that `stdout` does not contain `unexpected`.
     #[track_caller]
     pub fn assert_stdout_not_contains<S: AsRef<str>>(&self, unexpected: S) -> &Self {
-        assert_not_contains(&self.stdout_utf8(), unexpected.as_ref());
+        assert_not_contains(&self.stdout_utf8(), unexpected);
         self
     }
 
     /// Checks that `stdout` contains `expected`.
     #[track_caller]
     pub fn assert_stdout_contains<S: AsRef<str>>(&self, expected: S) -> &Self {
-        assert_contains(&self.stdout_utf8(), expected.as_ref());
+        assert_contains(&self.stdout_utf8(), expected);
         self
     }
 
@@ -206,14 +207,14 @@ impl CompletedProcess {
     /// Checks that `stderr` contains `expected`.
     #[track_caller]
     pub fn assert_stderr_contains<S: AsRef<str>>(&self, expected: S) -> &Self {
-        assert_contains(&self.stderr_utf8(), expected.as_ref());
+        assert_contains(&self.stderr_utf8(), expected);
         self
     }
 
     /// Checks that `stderr` does not contain `unexpected`.
     #[track_caller]
     pub fn assert_stderr_not_contains<S: AsRef<str>>(&self, unexpected: S) -> &Self {
-        assert_not_contains(&self.stdout_utf8(), unexpected.as_ref());
+        assert_not_contains(&self.stdout_utf8(), unexpected);
         self
     }
 
diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs
index 3e0bdc1c6f6..24fa88af82e 100644
--- a/src/tools/run-make-support/src/diff/mod.rs
+++ b/src/tools/run-make-support/src/diff/mod.rs
@@ -87,9 +87,7 @@ impl Diff {
         self
     }
 
-    #[track_caller]
-    pub fn run(&mut self) {
-        self.drop_bomb.defuse();
+    fn run_common(&self) -> (&str, &str, String, String) {
         let expected = self.expected.as_ref().expect("expected text not set");
         let mut actual = self.actual.as_ref().expect("actual text not set").to_string();
         let expected_name = self.expected_name.as_ref().unwrap();
@@ -104,6 +102,14 @@ impl Diff {
             .header(expected_name, actual_name)
             .to_string();
 
+        (expected_name, actual_name, output, actual)
+    }
+
+    #[track_caller]
+    pub fn run(&mut self) {
+        self.drop_bomb.defuse();
+        let (expected_name, actual_name, output, actual) = self.run_common();
+
         if !output.is_empty() {
             // If we can bless (meaning we have a file to write into and the `RUSTC_BLESS_TEST`
             // environment variable set), then we write into the file and return.
@@ -120,4 +126,26 @@ impl Diff {
             )
         }
     }
+
+    #[track_caller]
+    pub fn run_fail(&mut self) {
+        self.drop_bomb.defuse();
+        let (expected_name, actual_name, output, actual) = self.run_common();
+
+        if output.is_empty() {
+            // If we can bless (meaning we have a file to write into and the `RUSTC_BLESS_TEST`
+            // environment variable set), then we write into the file and return.
+            if let Some(ref expected_file) = self.expected_file {
+                if std::env::var("RUSTC_BLESS_TEST").is_ok() {
+                    println!("Blessing `{}`", expected_file.display());
+                    fs_wrapper::write(expected_file, actual);
+                    return;
+                }
+            }
+            panic!(
+                "test failed: `{}` is not different from `{}`\n\n{}",
+                expected_name, actual_name, output
+            )
+        }
+    }
 }
diff --git a/src/tools/run-make-support/src/fs_wrapper.rs b/src/tools/run-make-support/src/fs_wrapper.rs
index 8a2bfce8b4a..0f0d6f6618c 100644
--- a/src/tools/run-make-support/src/fs_wrapper.rs
+++ b/src/tools/run-make-support/src/fs_wrapper.rs
@@ -1,7 +1,7 @@
 use std::fs;
 use std::path::Path;
 
-/// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message.
 #[track_caller]
 pub fn remove_file<P: AsRef<Path>>(path: P) {
     fs::remove_file(path.as_ref())
@@ -18,21 +18,21 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
     ));
 }
 
-/// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message.
 #[track_caller]
 pub fn create_file<P: AsRef<Path>>(path: P) {
     fs::File::create(path.as_ref())
         .expect(&format!("the file in path \"{}\" could not be created", path.as_ref().display()));
 }
 
-/// A wrapper around [`std::fs::read`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::read`] which includes the file path in the panic message.
 #[track_caller]
 pub fn read<P: AsRef<Path>>(path: P) -> Vec<u8> {
     fs::read(path.as_ref())
         .expect(&format!("the file in path \"{}\" could not be read", path.as_ref().display()))
 }
 
-/// A wrapper around [`std::fs::read_to_string`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::read_to_string`] which includes the file path in the panic message.
 #[track_caller]
 pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
     fs::read_to_string(path.as_ref()).expect(&format!(
@@ -41,14 +41,14 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
     ))
 }
 
-/// A wrapper around [`std::fs::read_dir`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::read_dir`] which includes the file path in the panic message.
 #[track_caller]
 pub fn read_dir<P: AsRef<Path>>(path: P) -> fs::ReadDir {
     fs::read_dir(path.as_ref())
         .expect(&format!("the directory in path \"{}\" could not be read", path.as_ref().display()))
 }
 
-/// A wrapper around [`std::fs::write`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::write`] which includes the file path in the panic message.
 #[track_caller]
 pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
     fs::write(path.as_ref(), contents.as_ref()).expect(&format!(
@@ -57,7 +57,7 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
     ));
 }
 
-/// A wrapper around [`std::fs::remove_dir_all`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::remove_dir_all`] which includes the file path in the panic message.
 #[track_caller]
 pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
     fs::remove_dir_all(path.as_ref()).expect(&format!(
@@ -66,7 +66,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
     ));
 }
 
-/// A wrapper around [`std::fs::create_dir`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::create_dir`] which includes the file path in the panic message.
 #[track_caller]
 pub fn create_dir<P: AsRef<Path>>(path: P) {
     fs::create_dir(path.as_ref()).expect(&format!(
@@ -75,7 +75,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) {
     ));
 }
 
-/// A wrapper around [`std::fs::create_dir_all`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::create_dir_all`] which includes the file path in the panic message.
 #[track_caller]
 pub fn create_dir_all<P: AsRef<Path>>(path: P) {
     fs::create_dir_all(path.as_ref()).expect(&format!(
@@ -84,7 +84,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) {
     ));
 }
 
-/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message..
+/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message.
 #[track_caller]
 pub fn metadata<P: AsRef<Path>>(path: P) -> fs::Metadata {
     fs::metadata(path.as_ref()).expect(&format!(
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index df417722e02..5655318267a 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -35,7 +35,7 @@ pub use llvm::{
     LlvmProfdata, LlvmReadobj,
 };
 pub use run::{cmd, run, run_fail, run_with_args};
-pub use rustc::{aux_build, rustc, Rustc};
+pub use rustc::{aux_build, bare_rustc, rustc, Rustc};
 pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
 
 #[track_caller]
@@ -261,6 +261,62 @@ pub fn test_while_readonly<P: AsRef<Path>, F: FnOnce() + std::panic::UnwindSafe>
     success.unwrap();
 }
 
+/// Browse the directory `path` non-recursively and return all files which respect the parameters
+/// outlined by `closure`.
+#[track_caller]
+pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>(
+    path: P,
+    filter: F,
+) -> Vec<PathBuf> {
+    let mut matching_files = Vec::new();
+    for entry in fs_wrapper::read_dir(path) {
+        let entry = entry.expect("failed to read directory entry.");
+        let path = entry.path();
+
+        if path.is_file() && filter(&path) {
+            matching_files.push(path);
+        }
+    }
+    matching_files
+}
+
+/// Returns true if the filename at `path` starts with `prefix`.
+pub fn has_prefix<P: AsRef<Path>>(path: P, prefix: &str) -> bool {
+    path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix))
+}
+
+/// Returns true if the filename at `path` has the extension `extension`.
+pub fn has_extension<P: AsRef<Path>>(path: P, extension: &str) -> bool {
+    path.as_ref().extension().is_some_and(|ext| ext == extension)
+}
+
+/// Returns true if the filename at `path` does not contain `expected`.
+pub fn not_contains<P: AsRef<Path>>(path: P, expected: &str) -> bool {
+    !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected))
+}
+
+/// Returns true if the filename at `path` is not in `expected`.
+pub fn filename_not_in_denylist<P: AsRef<Path>, V: AsRef<[String]>>(path: P, expected: V) -> bool {
+    let expected = expected.as_ref();
+    path.as_ref()
+        .file_name()
+        .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned()))
+}
+
+/// Gathers all files in the current working directory that have the extension `ext`, and counts
+/// the number of lines within that contain a match with the regex pattern `re`.
+pub fn count_regex_matches_in_files_with_extension(re: &regex::Regex, ext: &str) -> usize {
+    let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext));
+
+    let mut count = 0;
+    for file in fetched_files {
+        let content = fs_wrapper::read_to_string(file);
+        count += content.lines().filter(|line| re.is_match(&line)).count();
+    }
+
+    count
+}
+
 /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
 /// available on the platform!
 #[track_caller]
@@ -321,8 +377,9 @@ pub fn set_host_rpath(cmd: &mut Command) {
 /// Read the contents of a file that cannot simply be read by
 /// read_to_string, due to invalid utf8 data, then assert that it contains `expected`.
 #[track_caller]
-pub fn invalid_utf8_contains<P: AsRef<Path>>(path: P, expected: &str) {
+pub fn invalid_utf8_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) {
     let buffer = fs_wrapper::read(path.as_ref());
+    let expected = expected.as_ref();
     if !String::from_utf8_lossy(&buffer).contains(expected) {
         eprintln!("=== FILE CONTENTS (LOSSY) ===");
         eprintln!("{}", String::from_utf8_lossy(&buffer));
@@ -335,8 +392,9 @@ pub fn invalid_utf8_contains<P: AsRef<Path>>(path: P, expected: &str) {
 /// Read the contents of a file that cannot simply be read by
 /// read_to_string, due to invalid utf8 data, then assert that it does not contain `expected`.
 #[track_caller]
-pub fn invalid_utf8_not_contains<P: AsRef<Path>>(path: P, expected: &str) {
+pub fn invalid_utf8_not_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) {
     let buffer = fs_wrapper::read(path.as_ref());
+    let expected = expected.as_ref();
     if String::from_utf8_lossy(&buffer).contains(expected) {
         eprintln!("=== FILE CONTENTS (LOSSY) ===");
         eprintln!("{}", String::from_utf8_lossy(&buffer));
@@ -409,7 +467,9 @@ pub fn read_dir<F: FnMut(&Path)>(dir: impl AsRef<Path>, mut callback: F) {
 
 /// Check that `actual` is equal to `expected`. Panic otherwise.
 #[track_caller]
-pub fn assert_equals(actual: &str, expected: &str) {
+pub fn assert_equals<S1: AsRef<str>, S2: AsRef<str>>(actual: S1, expected: S2) {
+    let actual = actual.as_ref();
+    let expected = expected.as_ref();
     if actual != expected {
         eprintln!("=== ACTUAL TEXT ===");
         eprintln!("{}", actual);
@@ -421,7 +481,9 @@ pub fn assert_equals(actual: &str, expected: &str) {
 
 /// Check that `haystack` contains `needle`. Panic otherwise.
 #[track_caller]
-pub fn assert_contains(haystack: &str, needle: &str) {
+pub fn assert_contains<S1: AsRef<str>, S2: AsRef<str>>(haystack: S1, needle: S2) {
+    let haystack = haystack.as_ref();
+    let needle = needle.as_ref();
     if !haystack.contains(needle) {
         eprintln!("=== HAYSTACK ===");
         eprintln!("{}", haystack);
@@ -433,7 +495,9 @@ pub fn assert_contains(haystack: &str, needle: &str) {
 
 /// Check that `haystack` does not contain `needle`. Panic otherwise.
 #[track_caller]
-pub fn assert_not_contains(haystack: &str, needle: &str) {
+pub fn assert_not_contains<S1: AsRef<str>, S2: AsRef<str>>(haystack: S1, needle: S2) {
+    let haystack = haystack.as_ref();
+    let needle = needle.as_ref();
     if haystack.contains(needle) {
         eprintln!("=== HAYSTACK ===");
         eprintln!("{}", haystack);
diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs
index 7f42223bf7f..4c9e9a53230 100644
--- a/src/tools/run-make-support/src/llvm.rs
+++ b/src/tools/run-make-support/src/llvm.rs
@@ -180,6 +180,13 @@ impl LlvmFilecheck {
         self.cmd.arg(path.as_ref());
         self
     }
+
+    /// `--input-file` option.
+    pub fn input_file<P: AsRef<Path>>(&mut self, input_file: P) -> &mut Self {
+        self.cmd.arg("--input-file");
+        self.cmd.arg(input_file.as_ref());
+        self
+    }
 }
 
 impl LlvmObjdump {
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index df843d74fc9..a2a7c8064dc 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -10,6 +10,12 @@ pub fn rustc() -> Rustc {
     Rustc::new()
 }
 
+/// Construct a plain `rustc` invocation with no flags set.
+#[track_caller]
+pub fn bare_rustc() -> Rustc {
+    Rustc::bare()
+}
+
 /// Construct a new `rustc` aux-build invocation.
 #[track_caller]
 pub fn aux_build() -> Rustc {
@@ -30,7 +36,6 @@ fn setup_common() -> Command {
     let rustc = env_var("RUSTC");
     let mut cmd = Command::new(rustc);
     set_host_rpath(&mut cmd);
-    cmd.arg("-L").arg(cwd());
     cmd
 }
 
@@ -40,6 +45,14 @@ impl Rustc {
     /// Construct a new `rustc` invocation.
     #[track_caller]
     pub fn new() -> Self {
+        let mut cmd = setup_common();
+        cmd.arg("-L").arg(cwd());
+        Self { cmd }
+    }
+
+    /// Construct a bare `rustc` invocation with no flags set.
+    #[track_caller]
+    pub fn bare() -> Self {
         let cmd = setup_common();
         Self { cmd }
     }
@@ -86,7 +99,8 @@ impl Rustc {
     }
 
     /// Specify type(s) of output files to generate.
-    pub fn emit(&mut self, kinds: &str) -> &mut Self {
+    pub fn emit<S: AsRef<str>>(&mut self, kinds: S) -> &mut Self {
+        let kinds = kinds.as_ref();
         self.cmd.arg(format!("--emit={kinds}"));
         self
     }
@@ -107,7 +121,11 @@ impl Rustc {
     }
 
     /// Remap source path prefixes in all output.
-    pub fn remap_path_prefix<P: AsRef<Path>>(&mut self, from: P, to: P) -> &mut Self {
+    pub fn remap_path_prefix<P: AsRef<Path>, P2: AsRef<Path>>(
+        &mut self,
+        from: P,
+        to: P2,
+    ) -> &mut Self {
         let from = from.as_ref().to_string_lossy();
         let to = to.as_ref().to_string_lossy();
 
@@ -201,7 +219,8 @@ impl Rustc {
     }
 
     /// Specify the target triple, or a path to a custom target json spec file.
-    pub fn target(&mut self, target: &str) -> &mut Self {
+    pub fn target<S: AsRef<str>>(&mut self, target: S) -> &mut Self {
+        let target = target.as_ref();
         self.cmd.arg(format!("--target={target}"));
         self
     }
diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
index fb00427b1c1..2be962ad888 100644
--- a/src/tools/run-make-support/src/rustdoc.rs
+++ b/src/tools/run-make-support/src/rustdoc.rs
@@ -104,7 +104,8 @@ impl Rustdoc {
     }
 
     /// Specify the target triple, or a path to a custom target json spec file.
-    pub fn target(&mut self, target: &str) -> &mut Self {
+    pub fn target<S: AsRef<str>>(&mut self, target: S) -> &mut Self {
+        let target = target.as_ref();
         self.cmd.arg(format!("--target={target}"));
         self
     }
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
index 14238e2fed5..f16d814b9f0 100644
--- a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
@@ -241,11 +241,3 @@ impl Parse for QueryGroup {
         Ok(QueryGroup { group_path })
     }
 }
-
-struct Nothing;
-
-impl Parse for Nothing {
-    fn parse(_input: ParseStream<'_>) -> syn::Result<Self> {
-        Ok(Nothing)
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/stdx/src/anymap.rs b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
index d189b56a468..4eafcfb060f 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
@@ -68,8 +68,6 @@ pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeId
 /// The type parameter `A` allows you to use a different value type; normally you will want
 /// it to be `core::any::Any` (also known as `std::any::Any`), but there are other choices:
 ///
-/// - If you want the entire map to be cloneable, use `CloneAny` instead of `Any`; with
-///   that, you can only add types that implement `Clone` to the map.
 /// - You can add on `+ Send` or `+ Send + Sync` (e.g. `Map<dyn Any + Send>`) to add those
 ///   auto traits.
 ///
@@ -79,9 +77,6 @@ pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeId
 ///   also spelled [`AnyMap`] for convenience.
 /// - <code>[Map]&lt;dyn [core::any::Any] + Send&gt;</code>
 /// - <code>[Map]&lt;dyn [core::any::Any] + Send + Sync&gt;</code>
-/// - <code>[Map]&lt;dyn [CloneAny]&gt;</code>
-/// - <code>[Map]&lt;dyn [CloneAny] + Send&gt;</code>
-/// - <code>[Map]&lt;dyn [CloneAny] + Send + Sync&gt;</code>
 ///
 /// ## Example
 ///
@@ -205,12 +200,6 @@ mod tests {
         assert_debug::<Map<dyn Any>>();
         assert_debug::<Map<dyn Any + Send>>();
         assert_debug::<Map<dyn Any + Send + Sync>>();
-        assert_send::<Map<dyn CloneAny + Send>>();
-        assert_send::<Map<dyn CloneAny + Send + Sync>>();
-        assert_sync::<Map<dyn CloneAny + Send + Sync>>();
-        assert_debug::<Map<dyn CloneAny>>();
-        assert_debug::<Map<dyn CloneAny + Send>>();
-        assert_debug::<Map<dyn CloneAny + Send + Sync>>();
     }
 
     #[test]
@@ -232,53 +221,6 @@ mod tests {
     }
 }
 
-// impl some traits for dyn Any
-use core::fmt;
-
-#[doc(hidden)]
-pub trait CloneToAny {
-    /// Clone `self` into a new `Box<dyn CloneAny>` object.
-    fn clone_to_any(&self) -> Box<dyn CloneAny>;
-}
-
-impl<T: Any + Clone> CloneToAny for T {
-    #[inline]
-    fn clone_to_any(&self) -> Box<dyn CloneAny> {
-        Box::new(self.clone())
-    }
-}
-
-macro_rules! impl_clone {
-    ($t:ty) => {
-        impl Clone for Box<$t> {
-            #[inline]
-            fn clone(&self) -> Box<$t> {
-                // SAFETY: this dance is to reapply any Send/Sync marker. I’m not happy about this
-                // approach, given that I used to do it in safe code, but then came a dodgy
-                // future-compatibility warning where_clauses_object_safety, which is spurious for
-                // auto traits but still super annoying (future-compatibility lints seem to mean
-                // your bin crate needs a corresponding allow!). Although I explained my plight¹
-                // and it was all explained and agreed upon, no action has been taken. So I finally
-                // caved and worked around it by doing it this way, which matches what’s done for
-                // core::any², so it’s probably not *too* bad.
-                //
-                // ¹ https://github.com/rust-lang/rust/issues/51443#issuecomment-421988013
-                // ² https://github.com/rust-lang/rust/blob/e7825f2b690c9a0d21b6f6d84c404bb53b151b38/library/alloc/src/boxed.rs#L1613-L1616
-                let clone: Box<dyn CloneAny> = (**self).clone_to_any();
-                let raw: *mut dyn CloneAny = Box::into_raw(clone);
-                unsafe { Box::from_raw(raw as *mut $t) }
-            }
-        }
-
-        impl fmt::Debug for $t {
-            #[inline]
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                f.pad(stringify!($t))
-            }
-        }
-    };
-}
-
 /// Methods for downcasting from an `Any`-like trait object.
 ///
 /// This should only be implemented on trait objects for subtraits of `Any`, though you can
@@ -350,16 +292,3 @@ macro_rules! implement {
 implement!(Any);
 implement!(Any + Send);
 implement!(Any + Send + Sync);
-
-/// [`Any`], but with cloning.
-///
-/// Every type with no non-`'static` references that implements `Clone` implements `CloneAny`.
-/// See [`core::any`] for more details on `Any` in general.
-pub trait CloneAny: Any + CloneToAny {}
-impl<T: Any + Clone> CloneAny for T {}
-implement!(CloneAny);
-implement!(CloneAny + Send);
-implement!(CloneAny + Send + Sync);
-impl_clone!(dyn CloneAny);
-impl_clone!(dyn CloneAny + Send);
-impl_clone!(dyn CloneAny + Send + Sync);
diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs
index 565d19d863f..c211b34850a 100644
--- a/src/tools/rust-installer/src/combiner.rs
+++ b/src/tools/rust-installer/src/combiner.rs
@@ -55,6 +55,12 @@ actor! {
         /// The formats used to compress the tarball
         #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
+
+        /// Modification time that will be set for all files added to the archive.
+        /// The default is the date of the first Rust commit from 2006.
+        /// This serves for better reproducibility of the archives.
+        #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)]
+        override_file_mtime: u64,
     }
 }
 
@@ -145,7 +151,8 @@ impl Combiner {
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
             .compression_profile(self.compression_profile)
-            .compression_formats(self.compression_formats);
+            .compression_formats(self.compression_formats)
+            .override_file_mtime(self.override_file_mtime);
         tarballer.run()?;
 
         Ok(())
diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs
index b101e67d8df..035a394deeb 100644
--- a/src/tools/rust-installer/src/generator.rs
+++ b/src/tools/rust-installer/src/generator.rs
@@ -61,6 +61,12 @@ actor! {
         /// The formats used to compress the tarball
         #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
+
+        /// Modification time that will be set for all files added to the archive.
+        /// The default is the date of the first Rust commit from 2006.
+        /// This serves for better reproducibility of the archives.
+        #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)]
+        override_file_mtime: u64,
     }
 }
 
@@ -114,7 +120,8 @@ impl Generator {
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
             .compression_profile(self.compression_profile)
-            .compression_formats(self.compression_formats);
+            .compression_formats(self.compression_formats)
+            .override_file_mtime(self.override_file_mtime);
         tarballer.run()?;
 
         Ok(())
diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs
index 2f093e7ad17..b5e87a66ffc 100644
--- a/src/tools/rust-installer/src/tarballer.rs
+++ b/src/tools/rust-installer/src/tarballer.rs
@@ -32,6 +32,12 @@ actor! {
         /// The formats used to compress the tarball.
         #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
+
+        /// Modification time that will be set for all files added to the archive.
+        /// The default is the date of the first Rust commit from 2006.
+        /// This serves for better reproducibility of the archives.
+        #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)]
+        override_file_mtime: u64,
     }
 }
 
@@ -65,6 +71,8 @@ impl Tarballer {
         let buf = BufWriter::with_capacity(1024 * 1024, encoder);
         let mut builder = Builder::new(buf);
         // Make uid, gid and mtime deterministic to improve reproducibility
+        // The modification time of directories will be set to the date of the first Rust commit.
+        // The modification time of files will be set to `override_file_mtime` (see `append_path`).
         builder.mode(HeaderMode::Deterministic);
 
         let pool = rayon::ThreadPoolBuilder::new().num_threads(2).build().unwrap();
@@ -77,7 +85,7 @@ impl Tarballer {
             }
             for path in files {
                 let src = Path::new(&self.work_dir).join(&path);
-                append_path(&mut builder, &src, &path)
+                append_path(&mut builder, &src, &path, self.override_file_mtime)
                     .with_context(|| format!("failed to tar file '{}'", src.display()))?;
             }
             builder
@@ -93,10 +101,16 @@ impl Tarballer {
     }
 }
 
-fn append_path<W: Write>(builder: &mut Builder<W>, src: &Path, path: &String) -> Result<()> {
+fn append_path<W: Write>(
+    builder: &mut Builder<W>,
+    src: &Path,
+    path: &String,
+    override_file_mtime: u64,
+) -> Result<()> {
     let stat = symlink_metadata(src)?;
     let mut header = Header::new_gnu();
     header.set_metadata_in_mode(&stat, HeaderMode::Deterministic);
+    header.set_mtime(override_file_mtime);
 
     if stat.file_type().is_symlink() {
         let link = read_link(src)?;
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index c0bf9482b11..c826547e9d0 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -484,21 +484,25 @@ fn rewrite_generic_args(
     span: Span,
 ) -> Option<String> {
     match gen_args {
-        ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
-            let args = data
-                .args
-                .iter()
-                .map(|x| match x {
-                    ast::AngleBracketedArg::Arg(generic_arg) => {
-                        SegmentParam::from_generic_arg(generic_arg)
-                    }
-                    ast::AngleBracketedArg::Constraint(constraint) => {
-                        SegmentParam::Binding(constraint)
-                    }
-                })
-                .collect::<Vec<_>>();
+        ast::GenericArgs::AngleBracketed(ref data) => {
+            if data.args.is_empty() {
+                Some("".to_owned())
+            } else {
+                let args = data
+                    .args
+                    .iter()
+                    .map(|x| match x {
+                        ast::AngleBracketedArg::Arg(generic_arg) => {
+                            SegmentParam::from_generic_arg(generic_arg)
+                        }
+                        ast::AngleBracketedArg::Constraint(constraint) => {
+                            SegmentParam::Binding(constraint)
+                        }
+                    })
+                    .collect::<Vec<_>>();
 
-            overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
+                overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
+            }
         }
         ast::GenericArgs::Parenthesized(ref data) => format_function_type(
             data.inputs.iter().map(|x| &**x),
@@ -508,7 +512,7 @@ fn rewrite_generic_args(
             context,
             shape,
         ),
-        _ => Some("".to_owned()),
+        ast::GenericArgs::ParenthesizedElided(..) => Some("(..)".to_owned()),
     }
 }
 
diff --git a/src/tools/rustfmt/tests/target/return-type-notation.rs b/src/tools/rustfmt/tests/target/return-type-notation.rs
new file mode 100644
index 00000000000..0f26e7e272b
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/return-type-notation.rs
@@ -0,0 +1,10 @@
+fn rtn()
+where
+    T: Trait<method(..): Send + 'static>,
+    T::method(..): Send + 'static,
+{
+}
+
+fn test() {
+    let x: T::method(..);
+}
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 741bb46d1a7..d26d6fe360d 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -23,9 +23,6 @@ run-make/dep-info-spaces/Makefile
 run-make/dep-info/Makefile
 run-make/dump-ice-to-disk/Makefile
 run-make/dump-mono-stats/Makefile
-run-make/dylib-chain/Makefile
-run-make/emit-path-unhashed/Makefile
-run-make/emit-shared-files/Makefile
 run-make/emit-to-stdout/Makefile
 run-make/env-dep-info/Makefile
 run-make/export-executable-symbols/Makefile
@@ -47,11 +44,9 @@ run-make/fmt-write-bloat/Makefile
 run-make/foreign-double-unwind/Makefile
 run-make/foreign-exceptions/Makefile
 run-make/foreign-rust-exceptions/Makefile
-run-make/include_bytes_deps/Makefile
 run-make/incr-add-rust-src-component/Makefile
 run-make/incr-foreign-head-span/Makefile
 run-make/interdependent-c-libraries/Makefile
-run-make/intrinsic-unreachable/Makefile
 run-make/issue-107094/Makefile
 run-make/issue-109934-lto-debuginfo/Makefile
 run-make/issue-14698/Makefile
@@ -64,9 +59,6 @@ run-make/issue-28595/Makefile
 run-make/issue-33329/Makefile
 run-make/issue-35164/Makefile
 run-make/issue-36710/Makefile
-run-make/issue-37839/Makefile
-run-make/issue-40535/Makefile
-run-make/issue-47384/Makefile
 run-make/issue-47551/Makefile
 run-make/issue-69368/Makefile
 run-make/issue-83045/Makefile
@@ -85,7 +77,6 @@ run-make/link-cfg/Makefile
 run-make/link-framework/Makefile
 run-make/link-path-order/Makefile
 run-make/linkage-attr-on-static/Makefile
-run-make/llvm-ident/Makefile
 run-make/long-linker-command-lines-cmd-exe/Makefile
 run-make/long-linker-command-lines/Makefile
 run-make/longjmp-across-rust/Makefile
@@ -99,31 +90,21 @@ run-make/metadata-dep-info/Makefile
 run-make/min-global-align/Makefile
 run-make/missing-crate-dependency/Makefile
 run-make/mixing-libs/Makefile
-run-make/msvc-opt-minsize/Makefile
 run-make/native-link-modifier-bundle/Makefile
 run-make/native-link-modifier-whole-archive/Makefile
 run-make/no-alloc-shim/Makefile
 run-make/no-builtins-attribute/Makefile
 run-make/no-duplicate-libs/Makefile
 run-make/obey-crate-type-flag/Makefile
-run-make/optimization-remarks-dir-pgo/Makefile
-run-make/optimization-remarks-dir/Makefile
-run-make/output-type-permutations/Makefile
 run-make/panic-abort-eh_frame/Makefile
-run-make/pass-linker-flags-flavor/Makefile
-run-make/pass-linker-flags-from-dep/Makefile
-run-make/pass-linker-flags/Makefile
 run-make/pass-non-c-like-enum-to-c/Makefile
 run-make/pdb-buildinfo-cl-cmd/Makefile
 run-make/pgo-gen-lto/Makefile
 run-make/pgo-gen-no-imp-symbols/Makefile
-run-make/pgo-gen/Makefile
 run-make/pgo-indirect-call-promotion/Makefile
-run-make/pgo-use/Makefile
 run-make/pointer-auth-link-with-c/Makefile
 run-make/print-calling-conventions/Makefile
 run-make/print-target-list/Makefile
-run-make/profile/Makefile
 run-make/prune-link-args/Makefile
 run-make/raw-dylib-alt-calling-convention/Makefile
 run-make/raw-dylib-c/Makefile
@@ -137,18 +118,13 @@ run-make/remap-path-prefix-dwarf/Makefile
 run-make/reproducible-build-2/Makefile
 run-make/reproducible-build/Makefile
 run-make/return-non-c-like-enum-from-c/Makefile
-run-make/rlib-chain/Makefile
 run-make/rlib-format-packed-bundled-libs-2/Makefile
 run-make/rlib-format-packed-bundled-libs-3/Makefile
 run-make/rlib-format-packed-bundled-libs/Makefile
-run-make/rmeta-preferred/Makefile
 run-make/rustc-macro-dep-files/Makefile
 run-make/sanitizer-cdylib-link/Makefile
 run-make/sanitizer-dylib-link/Makefile
 run-make/sanitizer-staticlib-link/Makefile
-run-make/sepcomp-cci-copies/Makefile
-run-make/sepcomp-inlining/Makefile
-run-make/sepcomp-separate/Makefile
 run-make/share-generics-dylib/Makefile
 run-make/silly-file-names/Makefile
 run-make/simd-ffi/Makefile
@@ -163,20 +139,10 @@ run-make/symbol-mangling-hashed/Makefile
 run-make/symbol-visibility/Makefile
 run-make/symbols-include-type-name/Makefile
 run-make/sysroot-crates-are-unstable/Makefile
-run-make/target-cpu-native/Makefile
-run-make/target-specs/Makefile
-run-make/target-without-atomic-cas/Makefile
 run-make/test-benches/Makefile
-run-make/test-harness/Makefile
 run-make/thumb-none-cortex-m/Makefile
 run-make/thumb-none-qemu/Makefile
-run-make/track-path-dep-info/Makefile
-run-make/track-pgo-dep-info/Makefile
 run-make/translation/Makefile
 run-make/type-mismatch-same-crate-name/Makefile
 run-make/unstable-flag-required/Makefile
-run-make/volatile-intrinsics/Makefile
-run-make/wasm-exceptions-nostd/Makefile
-run-make/wasm-override-linker/Makefile
-run-make/weird-output-filenames/Makefile
 run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index aa119819aaa..82fa43f581f 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -335,6 +335,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "proc-macro2",
     "psm",
     "pulldown-cmark",
+    "pulldown-cmark-escape",
     "punycode",
     "quote",
     "r-efi",
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 3e84bf3c34b..e8dff2dc261 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -112,7 +112,7 @@ pub fn check(
             let file = entry.path();
             let filename = file.file_name().unwrap().to_string_lossy();
             let filen_underscore = filename.replace('-', "_").replace(".rs", "");
-            let filename_is_gate_test = test_filen_gate(&filen_underscore, &mut features);
+            let filename_gate = test_filen_gate(&filen_underscore, &mut features);
 
             for (i, line) in contents.lines().enumerate() {
                 let mut err = |msg: &str| {
@@ -128,7 +128,7 @@ pub fn check(
                 };
                 match features.get_mut(feature_name) {
                     Some(f) => {
-                        if filename_is_gate_test {
+                        if filename_gate == Some(feature_name) {
                             err(&format!(
                                 "The file is already marked as gate test \
                                       through its name, no need for a \
@@ -259,18 +259,18 @@ fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
     r.captures(line).and_then(|c| c.get(1)).map(|m| m.as_str())
 }
 
-fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
+fn test_filen_gate<'f>(filen_underscore: &'f str, features: &mut Features) -> Option<&'f str> {
     let prefix = "feature_gate_";
-    if filen_underscore.starts_with(prefix) {
+    if let Some(suffix) = filen_underscore.strip_prefix(prefix) {
         for (n, f) in features.iter_mut() {
             // Equivalent to filen_underscore == format!("feature_gate_{n}")
-            if &filen_underscore[prefix.len()..] == n {
+            if suffix == n {
                 f.has_gate_test = true;
-                return true;
+                return Some(suffix);
             }
         }
     }
-    false
+    None
 }
 
 pub fn collect_lang_features(base_compiler_path: &Path, bad: &mut bool) -> Features {
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index 7e5656926ab..2f8abc77566 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -45,6 +45,8 @@ const EXCEPTION_PATHS: &[&str] = &[
     // pointer regardless of the target architecture. As a result,
     // we must use `#[cfg(windows)]` to conditionally compile the
     // correct `VaList` structure for windows.
+    "library/core/src/ffi/va_list.rs",
+    // We placed a linkage against Windows libraries here
     "library/core/src/ffi/mod.rs",
     "library/std/src/sys", // Platform-specific code for std lives here.
     "library/std/src/os",  // Platform-specific public interfaces
diff --git a/src/tools/tidy/src/run_make_tests.rs b/src/tools/tidy/src/run_make_tests.rs
index 2d9f8448a35..8d176787837 100644
--- a/src/tools/tidy/src/run_make_tests.rs
+++ b/src/tools/tidy/src/run_make_tests.rs
@@ -95,7 +95,7 @@ pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) {
             tidy_error!(
                 bad,
                 "Makefile `{}` no longer exists and should be removed from the exclusions in \
-                `src/tools/tidy/src/allowed_run_make_makefiles.txt`, you can run --bless to update \
+                `src/tools/tidy/src/allowed_run_make_makefiles.txt`, you can run `x test tidy --bless` to update \
                 the allow list",
                 p.display()
             );
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index e4d54d2a2b5..8e693c35adc 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -110,6 +110,7 @@ const ROOT_PROBLEMATIC_CONSTS: &[u32] = &[
     173390526, 721077,
 ];
 
+// Returns all permutations of problematic consts, over 2000 elements.
 fn generate_problematic_strings(
     consts: &[u32],
     letter_digit: &FxHashMap<char, char>,
@@ -319,6 +320,8 @@ pub fn check(path: &Path, bad: &mut bool) {
         ROOT_PROBLEMATIC_CONSTS,
         &[('A', '4'), ('B', '8'), ('E', '3')].iter().cloned().collect(),
     );
+    // This creates a RegexSet as regex contains performance optimizations to be able to deal with these over
+    // 2000 needles efficiently. This runs over the entire source code, so performance matters.
     let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap();
 
     walk(path, skip, &mut |entry, contents| {
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 95857502108..5e6992038e3 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -13,7 +13,7 @@ use std::path::{Path, PathBuf};
 // should all be 1000 or lower. Limits significantly smaller than 1000 are also
 // desirable, because large numbers of files are unwieldy in general. See issue
 // #73494.
-const ENTRY_LIMIT: u32 = 900;
+const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
 const ISSUES_ENTRY_LIMIT: u32 = 1672;
diff --git a/tests/assembly/asm-comments.rs b/tests/assembly/asm-comments.rs
new file mode 100644
index 00000000000..557009975dd
--- /dev/null
+++ b/tests/assembly/asm-comments.rs
@@ -0,0 +1,12 @@
+//@ assembly-output: emit-asm
+//@ only-x86_64
+// Check that comments in assembly get passed
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: test_comments:
+#[no_mangle]
+pub fn test_comments() {
+    // CHECK: example comment
+    unsafe { core::arch::asm!("nop // example comment") };
+}
diff --git a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
index 947faa165a9..d87ad41e70d 100644
--- a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
+++ b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs
@@ -1,6 +1,7 @@
 //
 //@ compile-flags:-Zprint-mono-items=eager
 //@ compile-flags:-Zinline-in-all-cgus
+//@ compile-flags:-Zinline-mir=no
 
 #![feature(start)]
 
diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs
index c6a8b7bbf37..34e52d38bbe 100644
--- a/tests/codegen/cast-target-abi.rs
+++ b/tests/codegen/cast-target-abi.rs
@@ -1,6 +1,7 @@
 // ignore-tidy-linelength
-//@ revisions:aarch64 loongarch64 powerpc64 sparc64
-//@ compile-flags: -O -C no-prepopulate-passes
+//@ revisions:aarch64 loongarch64 powerpc64 sparc64 x86_64
+// FIXME: Add `-Cllvm-args=--lint-abort-on-error` after LLVM 19
+//@ compile-flags: -O -C no-prepopulate-passes -C passes=lint
 
 //@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
 //@[aarch64] needs-llvm-components: arm
@@ -10,6 +11,8 @@
 //@[powerpc64] needs-llvm-components: powerpc
 //@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
 //@[sparc64] needs-llvm-components: sparc
+//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64] needs-llvm-components: x86
 
 // Tests that arguments with `PassMode::Cast` are handled correctly.
 
@@ -60,30 +63,261 @@ pub struct DoubleFloat {
     g: f32,
 }
 
-extern "C" {
-    fn receives_twou16s(x: TwoU16s);
-    fn returns_twou16s() -> TwoU16s;
+// On x86_64, this struct will be passed as `{ i64, i32 }`.
+// The load and store instructions will access 16 bytes, so we should allocate 16 bytes.
+#[repr(C)]
+pub struct Three32s {
+    a: u32,
+    b: u32,
+    c: u32,
+}
+
+// CHECK-LABEL: @receives_twou16s
+// aarch64-SAME:     ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]])
+// sparc64-SAME:     ([[ABI_TYPE:i64]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:i32]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_twou16s(x: TwoU16s) {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
+
+    // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+}
+
+// CHECK-LABEL: @returns_twou16s
+// powerpc64-SAME: sret([4 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_twou16s() -> TwoU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:2]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:2]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // sparc64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    TwoU16s { a: 0, b: 1 }
+}
+
+// CHECK-LABEL: @receives_fiveu16s
+// aarch64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// sparc64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:{ i64, i16 }]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_fiveu16s(x: FiveU16s) {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align [[RUST_ALIGN:2]]
+
+    // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+}
+
+// CHECK-LABEL: @returns_fiveu16s
+// powerpc64-SAME: sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_fiveu16s() -> FiveU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:2]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // sparc64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    FiveU16s { a: 0, b: 1, c: 2, d: 3, e: 4 }
+}
+
+// CHECK-LABEL: @receives_doubledouble
+// aarch64-SAME:     ([[ABI_TYPE:\[2 x double\]]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// sparc64-SAME:     ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_doubledouble(x: DoubleDouble) {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+
+    // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+}
+
+// CHECK-LABEL: @returns_doubledouble
+// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_doubledouble() -> DoubleDouble {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x double\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // sparc64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    DoubleDouble { f: 0., g: 1. }
+}
+
+// CHECK-LABEL: @receives_three32s
+// aarch64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// sparc64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:{ i64, i32 }]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_three32s(x: Three32s) {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]]
+
+    // CHECK: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
-    fn receives_fiveu16s(x: FiveU16s);
-    fn returns_fiveu16s() -> FiveU16s;
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+}
+
+// CHECK-LABEL: @returns_three32s
+// powerpc64-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_three32s() -> Three32s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:4]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // sparc64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    Three32s { a: 0, b: 0, c: 0 }
+}
+
+// These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @receives_doublefloat
+// loongarch64-LABEL: @receives_doublefloat
+// powerpc64-LABEL:   @receives_doublefloat
+// x86_64-LABEL:      @receives_doublefloat
+
+// aarch64-SAME:     ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// loongarch64-SAME: ([[ABI_TYPE:{ double, float }]] {{.*}}[[ABI_VALUE:%.+]])
+// powerpc64-SAME:   ([[ABI_TYPE:\[2 x i64\]]] {{.*}}[[ABI_VALUE:%.+]])
+// x86_64-SAME:      ([[ABI_TYPE:{ double, double }]] {{.*}}[[ABI_VALUE:%.+]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn receives_doublefloat(x: DoubleFloat) {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // powerpc64:   [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // powerpc64:   call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+}
+
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @returns_doublefloat
+// loongarch64-LABEL: @returns_doublefloat
+// powerpc64-LABEL:   @returns_doublefloat
+// x86_64-LABEL:      @returns_doublefloat
+
+// powerpc64-SAME: sret([16 x i8]) align [[RUST_ALIGN:8]] {{.*}}[[RET_PTR:%.*]])
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn returns_doublefloat() -> DoubleFloat {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
 
-    fn receives_doubledouble(x: DoubleDouble);
-    fn returns_doubledouble() -> DoubleDouble;
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
-    // These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
-    #[cfg(not(target_arch = "sparc64"))]
-    fn receives_doublefloat(x: DoubleFloat);
-    #[cfg(not(target_arch = "sparc64"))]
-    fn returns_doublefloat() -> DoubleFloat;
+    // aarch64:     ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // loongarch64: ret [[ABI_TYPE]] [[ABI_VALUE]]
+    // x86_64:      ret [[ABI_TYPE]] [[ABI_VALUE]]
+    DoubleFloat { f: 0., g: 0. }
 }
 
 // CHECK-LABEL: @call_twou16s
 #[no_mangle]
-pub unsafe fn call_twou16s() {
+pub fn call_twou16s() {
     // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
     // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
     // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
     // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
 
     // CHECK: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
 
@@ -93,6 +327,7 @@ pub unsafe fn call_twou16s() {
     // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i64]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:i32]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]])
     let x = TwoU16s { a: 1, b: 2 };
@@ -101,7 +336,7 @@ pub unsafe fn call_twou16s() {
 
 // CHECK-LABEL: @return_twou16s
 #[no_mangle]
-pub unsafe fn return_twou16s() -> TwoU16s {
+pub fn return_twou16s() -> TwoU16s {
     // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
 
     // powerpc64: [[RETVAL:%.+]] = alloca [4 x i8], align 2
@@ -112,34 +347,45 @@ pub unsafe fn return_twou16s() -> TwoU16s {
     // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
     // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
     // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [8 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [4 x i8], align [[ABI_ALIGN:4]]
 
     // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
     // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
     // sparc64:     [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [4 x i8], align [[RUST_ALIGN:2]]
 
     // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s()
     // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s()
     // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i64]] @returns_twou16s()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:i32]] @returns_twou16s()
 
     // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
     // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
     // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
     returns_twou16s()
 }
 
 // CHECK-LABEL: @call_fiveu16s
 #[no_mangle]
-pub unsafe fn call_fiveu16s() {
+pub fn call_fiveu16s() {
     // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
 
     // CHECK: [[RUST_ALLOCA:%.+]] = alloca [10 x i8], align 2
 
     // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false)
-    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i16 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
     // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]])
     let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 };
     receives_fiveu16s(x);
@@ -148,7 +394,7 @@ pub unsafe fn call_fiveu16s() {
 // CHECK-LABEL: @return_fiveu16s
 // CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] dereferenceable(10) [[RET_PTR:%.+]])
 #[no_mangle]
-pub unsafe fn return_fiveu16s() -> FiveU16s {
+pub fn return_fiveu16s() -> FiveU16s {
     // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
 
     // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]])
@@ -158,24 +404,28 @@ pub unsafe fn return_fiveu16s() -> FiveU16s {
     // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
     // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
     // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
 
     // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s()
     // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s()
     // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_fiveu16s()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i16 }]] @returns_fiveu16s()
 
     // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
     // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
     // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
     returns_fiveu16s()
 }
 
 // CHECK-LABEL: @call_doubledouble
 #[no_mangle]
-pub unsafe fn call_doubledouble() {
+pub fn call_doubledouble() {
     // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
 
     // CHECK: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
@@ -186,6 +436,7 @@ pub unsafe fn call_doubledouble() {
     // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]])
     let x = DoubleDouble { f: 1., g: 2. };
@@ -194,7 +445,7 @@ pub unsafe fn call_doubledouble() {
 
 // CHECK-LABEL: @return_doubledouble
 #[no_mangle]
-pub unsafe fn return_doubledouble() -> DoubleDouble {
+pub fn return_doubledouble() -> DoubleDouble {
     // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
 
     // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8
@@ -205,22 +456,27 @@ pub unsafe fn return_doubledouble() -> DoubleDouble {
     // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
     // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
     // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
 
     // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
     // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
     // sparc64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
 
     // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x double\]]] @returns_doubledouble()
     // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble()
     // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doubledouble()
 
     // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
     // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
     // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
     returns_doubledouble()
 }
 
@@ -229,27 +485,33 @@ pub unsafe fn return_doubledouble() -> DoubleDouble {
 // aarch64-LABEL:     @call_doublefloat
 // loongarch64-LABEL: @call_doublefloat
 // powerpc64-LABEL:   @call_doublefloat
+// x86_64-LABEL:      @call_doublefloat
 #[no_mangle]
-pub unsafe fn call_doublefloat() {
+pub fn call_doublefloat() {
     // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
-    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
     // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
 
     // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
     // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
     // powerpc64:   [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
 
     // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
     // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false)
     // powerpc64:   call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
 
     // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, float }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ double, double }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // aarch64:     call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
     // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
     // powerpc64:   call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // x86_64:      call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
     let x = DoubleFloat { f: 1., g: 2. };
     receives_doublefloat(x);
 }
@@ -259,8 +521,9 @@ pub unsafe fn call_doublefloat() {
 // aarch64-LABEL:     @return_doublefloat
 // loongarch64-LABEL: @return_doublefloat
 // powerpc64-LABEL:   @return_doublefloat
+// x86_64-LABEL:      @return_doublefloat
 #[no_mangle]
-pub unsafe fn return_doublefloat() -> DoubleFloat {
+pub fn return_doublefloat() -> DoubleFloat {
     // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
 
     // powerpc64: [[RETVAL:%.+]] = alloca [16 x i8], align 8
@@ -269,18 +532,72 @@ pub unsafe fn return_doublefloat() -> DoubleFloat {
     // The other targets copy the cast ABI type to an alloca.
 
     // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
-    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [12 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
 
     // aarch64:     [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
     // loongarch64: [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
+    // x86_64:      [[RUST_ALLOCA:%.+]] = alloca [16 x i8], align [[RUST_ALIGN:8]]
 
     // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_doublefloat()
     // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, float }]] @returns_doublefloat()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ double, double }]] @returns_doublefloat()
 
     // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
     // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
 
     // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
     // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
     returns_doublefloat()
 }
+
+// CHECK-LABEL: @call_three32s
+#[no_mangle]
+pub fn call_three32s() {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca [12 x i8], align [[RUST_ALIGN:4]]
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false)
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE:\[2 x i64\]]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      [[ABI_VALUE:%.+]] = load [[ABI_TYPE:{ i64, i32 }]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // CHECK: call void @receives_three32s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = Three32s { a: 1, b: 2, c: 3 };
+    receives_three32s(x);
+}
+
+// Regression test for #75839
+// CHECK-LABEL: @return_three32s(
+// CHECK-SAME: sret([12 x i8]) align [[RUST_ALIGN:4]] {{.*}}[[RUST_RETVAL:%.*]])
+#[no_mangle]
+pub fn return_three32s() -> Three32s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: call void @returns_three32s(ptr {{.+}} [[RUST_RETVAL]])
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+    // x86_64:      [[ABI_ALLOCA:%.+]] = alloca [16 x i8], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE:\[2 x i64\]]] @returns_three32s()
+    // x86_64:      [[ABI_VALUE:%.+]] = call [[ABI_TYPE:{ i64, i32 }]] @returns_three32s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // x86_64:      store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    // x86_64:      call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_RETVAL]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    returns_three32s()
+}
diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
index 614d5d94f62..a4b7c0caa6d 100644
--- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
+++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
@@ -1,5 +1,5 @@
 //@ revisions: linux apple
-//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
+//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes -C passes=lint
 
 //@[linux] compile-flags: --target x86_64-unknown-linux-gnu
 //@[linux] needs-llvm-components: x86
@@ -36,7 +36,7 @@ extern "C" {
 pub fn test() {
     let s = S { f1: 1, f2: 2, f3: 3 };
     unsafe {
-        // CHECK: [[ALLOCA:%.+]] = alloca [12 x i8], align 8
+        // CHECK: [[ALLOCA:%.+]] = alloca [16 x i8], align 8
         // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8
         // CHECK: call void @foo({ i64, i32 } [[LOAD]])
         foo(s);
diff --git a/tests/coverage-run-rustdoc/doctest.coverage b/tests/coverage-run-rustdoc/doctest.coverage
index 1bbf364759b..396811c5487 100644
--- a/tests/coverage-run-rustdoc/doctest.coverage
+++ b/tests/coverage-run-rustdoc/doctest.coverage
@@ -34,10 +34,10 @@ $DIR/doctest.rs:
    LL|       |//!
    LL|       |//! doctest returning a result:
    LL|      1|//! ```
-   LL|      1|//! #[derive(Debug, PartialEq)]
-   LL|      1|//! struct SomeError {
-   LL|      1|//!     msg: String,
-   LL|      1|//! }
+   LL|       |//! #[derive(Debug, PartialEq)]
+   LL|       |//! struct SomeError {
+   LL|       |//!     msg: String,
+   LL|       |//! }
    LL|      1|//! let mut res = Err(SomeError { msg: String::from("a message") });
    LL|      1|//! if res.is_ok() {
    LL|      0|//!     res?;
diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map
index 7d16372375a..9e5a4bdc60f 100644
--- a/tests/coverage/async.cov-map
+++ b/tests/coverage/async.cov-map
@@ -167,15 +167,16 @@ Number of file 0 mappings: 14
     = ((c6 + c7) + c8)
 
 Function name: async::j
-Raw bytes (53): 0x[01, 01, 02, 07, 0d, 05, 09, 09, 01, 35, 01, 13, 0c, 05, 14, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 03, 02, 01, 00, 02]
+Raw bytes (58): 0x[01, 01, 02, 07, 0d, 05, 09, 0a, 01, 35, 01, 00, 0d, 01, 0b, 0b, 00, 0c, 05, 01, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 03, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
 - expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3)
 - expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-Number of file 0 mappings: 9
-- Code(Counter(0)) at (prev + 53, 1) to (start + 19, 12)
-- Code(Counter(1)) at (prev + 20, 9) to (start + 0, 10)
+Number of file 0 mappings: 10
+- Code(Counter(0)) at (prev + 53, 1) to (start + 0, 13)
+- Code(Counter(0)) at (prev + 11, 11) to (start + 0, 12)
+- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 27)
 - Code(Counter(1)) at (prev + 0, 31) to (start + 0, 39)
 - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 10)
@@ -186,7 +187,7 @@ Number of file 0 mappings: 9
     = ((c1 + c2) + c3)
 
 Function name: async::j::c
-Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 37, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 01, 02, 05, 00, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 37, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 02, 0d, 00, 0e, 01, 02, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 1
@@ -194,40 +195,40 @@ Number of expressions: 1
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 55, 5) to (start + 1, 18)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 14)
-- Code(Expression(0, Sub)) at (prev + 10, 13) to (start + 0, 14)
+- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 14)
     = (c0 - c1)
 - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6)
 
 Function name: async::j::d
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 46, 05, 00, 17]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 3e, 05, 00, 17]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 70, 5) to (start + 0, 23)
+- Code(Counter(0)) at (prev + 62, 5) to (start + 0, 23)
 
 Function name: async::j::f
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 47, 05, 00, 17]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 3f, 05, 00, 17]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 71, 5) to (start + 0, 23)
+- Code(Counter(0)) at (prev + 63, 5) to (start + 0, 23)
 
 Function name: async::k (unused)
-Raw bytes (29): 0x[01, 01, 00, 05, 00, 4f, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
+Raw bytes (29): 0x[01, 01, 00, 05, 00, 47, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 5
-- Code(Zero) at (prev + 79, 1) to (start + 1, 12)
+- Code(Zero) at (prev + 71, 1) to (start + 1, 12)
 - Code(Zero) at (prev + 2, 14) to (start + 0, 16)
 - Code(Zero) at (prev + 1, 14) to (start + 0, 16)
 - Code(Zero) at (prev + 1, 14) to (start + 0, 16)
 - Code(Zero) at (prev + 2, 1) to (start + 0, 2)
 
 Function name: async::l
-Raw bytes (37): 0x[01, 01, 04, 01, 07, 05, 09, 0f, 02, 09, 05, 05, 01, 57, 01, 01, 0c, 02, 02, 0e, 00, 10, 05, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 0b, 02, 01, 00, 02]
+Raw bytes (37): 0x[01, 01, 04, 01, 07, 05, 09, 0f, 02, 09, 05, 05, 01, 4f, 01, 01, 0c, 02, 02, 0e, 00, 10, 05, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 0b, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 4
@@ -236,7 +237,7 @@ Number of expressions: 4
 - expression 2 operands: lhs = Expression(3, Add), rhs = Expression(0, Sub)
 - expression 3 operands: lhs = Counter(2), rhs = Counter(1)
 Number of file 0 mappings: 5
-- Code(Counter(0)) at (prev + 87, 1) to (start + 1, 12)
+- Code(Counter(0)) at (prev + 79, 1) to (start + 1, 12)
 - Code(Expression(0, Sub)) at (prev + 2, 14) to (start + 0, 16)
     = (c0 - (c1 + c2))
 - Code(Counter(1)) at (prev + 1, 14) to (start + 0, 16)
@@ -245,26 +246,26 @@ Number of file 0 mappings: 5
     = ((c2 + c1) + (c0 - (c1 + c2)))
 
 Function name: async::m
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 5f, 01, 00, 19]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 57, 01, 00, 19]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 95, 1) to (start + 0, 25)
+- Code(Counter(0)) at (prev + 87, 1) to (start + 0, 25)
 
 Function name: async::m::{closure#0} (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 5f, 19, 00, 22]
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 57, 19, 00, 22]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Zero) at (prev + 95, 25) to (start + 0, 34)
+- Code(Zero) at (prev + 87, 25) to (start + 0, 34)
 
 Function name: async::main
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 61, 01, 08, 02]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 59, 01, 08, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 97, 1) to (start + 8, 2)
+- Code(Counter(0)) at (prev + 89, 1) to (start + 8, 2)
 
diff --git a/tests/coverage/async.coverage b/tests/coverage/async.coverage
index e943911d310..f5473829b02 100644
--- a/tests/coverage/async.coverage
+++ b/tests/coverage/async.coverage
@@ -53,25 +53,15 @@
    LL|      1|}
    LL|       |
    LL|      1|fn j(x: u8) {
-   LL|      1|    // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`.
+   LL|       |    // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`.
    LL|      1|    fn c(x: u8) -> u8 {
    LL|      1|        if x == 8 {
-   LL|      1|            1 // This line appears covered, but the 1-character expression span covering the `1`
-                          ^0
-   LL|      1|              // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because
-   LL|      1|              // `fn j()` executes the open brace for the function body, followed by the function's
-   LL|      1|              // first executable statement, `match x`. Inner function declarations are not
-   LL|      1|              // "visible" to the MIR for `j()`, so the code region counts all lines between the
-   LL|      1|              // open brace and the first statement as executed, which is, in a sense, true.
-   LL|      1|              // `llvm-cov show` overcomes this kind of situation by showing the actual counts
-   LL|      1|              // of the enclosed coverages, (that is, the `1` expression was not executed, and
-   LL|      1|              // accurately displays a `0`).
-   LL|      1|        } else {
+   LL|      0|            1
+   LL|       |        } else {
    LL|      1|            0
-   LL|      1|        }
+   LL|       |        }
    LL|      1|    }
-   LL|      1|    fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed
-                  ^0
+   LL|      0|    fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed
    LL|      1|    fn f() -> u8 { 1 }
    LL|      1|    match x {
    LL|      1|        y if c(x) == y + 1 => { d(); }
diff --git a/tests/coverage/async.rs b/tests/coverage/async.rs
index 5018ade0125..7e6ad761ecd 100644
--- a/tests/coverage/async.rs
+++ b/tests/coverage/async.rs
@@ -54,15 +54,7 @@ fn j(x: u8) {
     // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`.
     fn c(x: u8) -> u8 {
         if x == 8 {
-            1 // This line appears covered, but the 1-character expression span covering the `1`
-              // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because
-              // `fn j()` executes the open brace for the function body, followed by the function's
-              // first executable statement, `match x`. Inner function declarations are not
-              // "visible" to the MIR for `j()`, so the code region counts all lines between the
-              // open brace and the first statement as executed, which is, in a sense, true.
-              // `llvm-cov show` overcomes this kind of situation by showing the actual counts
-              // of the enclosed coverages, (that is, the `1` expression was not executed, and
-              // accurately displays a `0`).
+            1
         } else {
             0
         }
diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map
index 0f2d5542f75..466aec8956e 100644
--- a/tests/coverage/attr/nested.cov-map
+++ b/tests/coverage/attr/nested.cov-map
@@ -1,18 +1,18 @@
 Function name: nested::closure_expr
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 44, 01, 01, 0f, 01, 0b, 05, 01, 02]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 3f, 01, 01, 0f, 01, 0b, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 68, 1) to (start + 1, 15)
+- Code(Counter(0)) at (prev + 63, 1) to (start + 1, 15)
 - Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2)
 
 Function name: nested::closure_tail
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 53, 01, 01, 0f, 01, 11, 05, 01, 02]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 4e, 01, 01, 0f, 01, 11, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 83, 1) to (start + 1, 15)
+- Code(Counter(0)) at (prev + 78, 1) to (start + 1, 15)
 - Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2)
 
diff --git a/tests/coverage/attr/nested.coverage b/tests/coverage/attr/nested.coverage
index bdd117b7dfa..2d64fe698ea 100644
--- a/tests/coverage/attr/nested.coverage
+++ b/tests/coverage/attr/nested.coverage
@@ -4,11 +4,6 @@
    LL|       |// Demonstrates the interaction between #[coverage(off)] and various kinds of
    LL|       |// nested function.
    LL|       |
-   LL|       |// FIXME(#126625): Coverage attributes should apply recursively to nested functions.
-   LL|       |// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`,
-   LL|       |// its lines can still be marked with misleading execution counts from its enclosing
-   LL|       |// function.
-   LL|       |
    LL|       |#[coverage(off)]
    LL|       |fn do_stuff() {}
    LL|       |
diff --git a/tests/coverage/attr/nested.rs b/tests/coverage/attr/nested.rs
index c7ff835f44f..8213e29b6fc 100644
--- a/tests/coverage/attr/nested.rs
+++ b/tests/coverage/attr/nested.rs
@@ -4,11 +4,6 @@
 // Demonstrates the interaction between #[coverage(off)] and various kinds of
 // nested function.
 
-// FIXME(#126625): Coverage attributes should apply recursively to nested functions.
-// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`,
-// its lines can still be marked with misleading execution counts from its enclosing
-// function.
-
 #[coverage(off)]
 fn do_stuff() {}
 
diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map
index ed77d7d17e6..d5fbac6ebf7 100644
--- a/tests/coverage/attr/off-on-sandwich.cov-map
+++ b/tests/coverage/attr/off-on-sandwich.cov-map
@@ -1,24 +1,27 @@
 Function name: off_on_sandwich::dense_a::dense_b
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 14, 05, 07, 06]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 0f, 05, 02, 12, 01, 07, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 20, 5) to (start + 7, 6)
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 15, 5) to (start + 2, 18)
+- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 6)
 
 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 26, 09, 0b, 0a]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 21, 09, 02, 17, 01, 0b, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 38, 9) to (start + 11, 10)
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 33, 9) to (start + 2, 23)
+- Code(Counter(0)) at (prev + 11, 9) to (start + 0, 10)
 
 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 29, 0d, 07, 0e]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 0d, 02, 1b, 01, 07, 0d, 00, 0e]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 41, 13) to (start + 7, 14)
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 36, 13) to (start + 2, 27)
+- Code(Counter(0)) at (prev + 7, 13) to (start + 0, 14)
 
diff --git a/tests/coverage/attr/off-on-sandwich.coverage b/tests/coverage/attr/off-on-sandwich.coverage
index 58c128b8342..675697906ee 100644
--- a/tests/coverage/attr/off-on-sandwich.coverage
+++ b/tests/coverage/attr/off-on-sandwich.coverage
@@ -4,11 +4,6 @@
    LL|       |// Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]`
    LL|       |// in nested functions.
    LL|       |
-   LL|       |// FIXME(#126625): Coverage attributes should apply recursively to nested functions.
-   LL|       |// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`,
-   LL|       |// its lines can still be marked with misleading execution counts from its enclosing
-   LL|       |// function.
-   LL|       |
    LL|       |#[coverage(off)]
    LL|       |fn do_stuff() {}
    LL|       |
@@ -20,10 +15,10 @@
    LL|      2|    fn dense_b() {
    LL|      2|        dense_c();
    LL|      2|        dense_c();
-   LL|      2|        #[coverage(off)]
-   LL|      2|        fn dense_c() {
-   LL|      2|            do_stuff();
-   LL|      2|        }
+   LL|       |        #[coverage(off)]
+   LL|       |        fn dense_c() {
+   LL|       |            do_stuff();
+   LL|       |        }
    LL|      2|    }
    LL|       |}
    LL|       |
@@ -41,10 +36,10 @@
    LL|      8|            fn sparse_d() {
    LL|      8|                sparse_e();
    LL|      8|                sparse_e();
-   LL|      8|                #[coverage(off)]
-   LL|      8|                fn sparse_e() {
-   LL|      8|                    do_stuff();
-   LL|      8|                }
+   LL|       |                #[coverage(off)]
+   LL|       |                fn sparse_e() {
+   LL|       |                    do_stuff();
+   LL|       |                }
    LL|      8|            }
    LL|      4|        }
    LL|       |    }
diff --git a/tests/coverage/attr/off-on-sandwich.rs b/tests/coverage/attr/off-on-sandwich.rs
index 6b21b180223..261634e0029 100644
--- a/tests/coverage/attr/off-on-sandwich.rs
+++ b/tests/coverage/attr/off-on-sandwich.rs
@@ -4,11 +4,6 @@
 // Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]`
 // in nested functions.
 
-// FIXME(#126625): Coverage attributes should apply recursively to nested functions.
-// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`,
-// its lines can still be marked with misleading execution counts from its enclosing
-// function.
-
 #[coverage(off)]
 fn do_stuff() {}
 
diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map
index 156947f4e21..eb5f94d1080 100644
--- a/tests/coverage/closure_macro.cov-map
+++ b/tests/coverage/closure_macro.cov-map
@@ -7,15 +7,16 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2)
 
 Function name: closure_macro::main
-Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 21, 01, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02]
+Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-Number of file 0 mappings: 5
+Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 33, 1) to (start + 1, 33)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15)
     = (c0 - c1)
+- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 84)
 - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11)
     = (c0 - c1)
diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map
index 0f2b4e01748..1286d663bd4 100644
--- a/tests/coverage/closure_macro_async.cov-map
+++ b/tests/coverage/closure_macro_async.cov-map
@@ -15,15 +15,16 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 35, 1) to (start + 0, 43)
 
 Function name: closure_macro_async::test::{closure#0}
-Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02]
+Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-Number of file 0 mappings: 5
+Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 35, 43) to (start + 1, 33)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15)
     = (c0 - c1)
+- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 84)
 - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11)
     = (c0 - c1)
diff --git a/tests/coverage/holes.cov-map b/tests/coverage/holes.cov-map
new file mode 100644
index 00000000000..9350bd9a405
--- /dev/null
+++ b/tests/coverage/holes.cov-map
@@ -0,0 +1,47 @@
+Function name: <holes::main::MyStruct>::_method (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 25, 09, 00, 1d]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 37, 9) to (start + 0, 29)
+
+Function name: holes::main
+Raw bytes (44): 0x[01, 01, 00, 08, 01, 08, 01, 06, 11, 01, 0f, 05, 00, 12, 01, 04, 05, 00, 12, 01, 07, 05, 00, 12, 01, 06, 05, 00, 12, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 01, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 8
+- Code(Counter(0)) at (prev + 8, 1) to (start + 6, 17)
+- Code(Counter(0)) at (prev + 15, 5) to (start + 0, 18)
+- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18)
+- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 18)
+- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 18)
+- Code(Counter(0)) at (prev + 6, 5) to (start + 3, 15)
+- Code(Counter(0)) at (prev + 10, 5) to (start + 3, 15)
+- Code(Counter(0)) at (prev + 10, 5) to (start + 1, 2)
+
+Function name: holes::main::_unused_fn (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 05, 00, 17]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 25, 5) to (start + 0, 23)
+
+Function name: holes::main::{closure#0} (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 12, 09, 02, 0a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 18, 9) to (start + 2, 10)
+
+Function name: holes::main::{closure#1} (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 3d, 09, 02, 0a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 61, 9) to (start + 2, 10)
+
diff --git a/tests/coverage/holes.coverage b/tests/coverage/holes.coverage
new file mode 100644
index 00000000000..6e65435f7e3
--- /dev/null
+++ b/tests/coverage/holes.coverage
@@ -0,0 +1,68 @@
+   LL|       |//@ edition: 2021
+   LL|       |
+   LL|       |// Nested items/closures should be treated as "holes", so that their spans are
+   LL|       |// not displayed as executable code in the enclosing function.
+   LL|       |
+   LL|       |use core::hint::black_box;
+   LL|       |
+   LL|      1|fn main() {
+   LL|      1|    black_box(());
+   LL|      1|
+   LL|      1|    // Splitting this across multiple lines makes it easier to see where the
+   LL|      1|    // coverage mapping regions begin and end.
+   LL|      1|    #[rustfmt::skip]
+   LL|      1|    let _closure =
+   LL|       |        |
+   LL|       |            _arg: (),
+   LL|       |        |
+   LL|      0|        {
+   LL|      0|            black_box(());
+   LL|      0|        }
+   LL|       |        ;
+   LL|       |
+   LL|      1|    black_box(());
+   LL|       |
+   LL|      0|    fn _unused_fn() {}
+   LL|       |
+   LL|      1|    black_box(());
+   LL|       |
+   LL|       |    struct MyStruct {
+   LL|       |        _x: u32,
+   LL|       |        _y: u32,
+   LL|       |    }
+   LL|       |
+   LL|      1|    black_box(());
+   LL|       |
+   LL|       |    impl MyStruct {
+   LL|      0|        fn _method(&self) {}
+   LL|       |    }
+   LL|       |
+   LL|      1|    black_box(());
+   LL|       |
+   LL|       |    macro_rules! _my_macro {
+   LL|       |        () => {};
+   LL|       |    }
+   LL|       |
+   LL|      1|    black_box(());
+   LL|      1|
+   LL|      1|    #[rustfmt::skip]
+   LL|      1|    let _const =
+   LL|       |        const
+   LL|       |        {
+   LL|       |            7 + 4
+   LL|       |        }
+   LL|       |        ;
+   LL|       |
+   LL|      1|    black_box(());
+   LL|      1|
+   LL|      1|    #[rustfmt::skip]
+   LL|      1|    let _async =
+   LL|       |        async
+   LL|      0|        {
+   LL|      0|            7 + 4
+   LL|      0|        }
+   LL|       |        ;
+   LL|       |
+   LL|      1|    black_box(());
+   LL|      1|}
+
diff --git a/tests/coverage/holes.rs b/tests/coverage/holes.rs
new file mode 100644
index 00000000000..b3a71e759c8
--- /dev/null
+++ b/tests/coverage/holes.rs
@@ -0,0 +1,67 @@
+//@ edition: 2021
+
+// Nested items/closures should be treated as "holes", so that their spans are
+// not displayed as executable code in the enclosing function.
+
+use core::hint::black_box;
+
+fn main() {
+    black_box(());
+
+    // Splitting this across multiple lines makes it easier to see where the
+    // coverage mapping regions begin and end.
+    #[rustfmt::skip]
+    let _closure =
+        |
+            _arg: (),
+        |
+        {
+            black_box(());
+        }
+        ;
+
+    black_box(());
+
+    fn _unused_fn() {}
+
+    black_box(());
+
+    struct MyStruct {
+        _x: u32,
+        _y: u32,
+    }
+
+    black_box(());
+
+    impl MyStruct {
+        fn _method(&self) {}
+    }
+
+    black_box(());
+
+    macro_rules! _my_macro {
+        () => {};
+    }
+
+    black_box(());
+
+    #[rustfmt::skip]
+    let _const =
+        const
+        {
+            7 + 4
+        }
+        ;
+
+    black_box(());
+
+    #[rustfmt::skip]
+    let _async =
+        async
+        {
+            7 + 4
+        }
+        ;
+
+    black_box(());
+}
diff --git a/tests/coverage/mcdc_if.cov-map b/tests/coverage/mcdc/if.cov-map
index 35a265684d2..9a7d15f700d 100644
--- a/tests/coverage/mcdc_if.cov-map
+++ b/tests/coverage/mcdc/if.cov-map
@@ -1,4 +1,4 @@
-Function name: mcdc_if::mcdc_check_a
+Function name: if::mcdc_check_a
 Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 0f, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -23,7 +23,7 @@ Number of file 0 mappings: 8
 - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2)
     = (c3 + (c2 + (c0 - c1)))
 
-Function name: mcdc_if::mcdc_check_b
+Function name: if::mcdc_check_b
 Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 17, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -48,7 +48,7 @@ Number of file 0 mappings: 8
 - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2)
     = (c3 + (c2 + (c0 - c1)))
 
-Function name: mcdc_if::mcdc_check_both
+Function name: if::mcdc_check_both
 Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 1f, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -73,7 +73,7 @@ Number of file 0 mappings: 8
 - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2)
     = (c3 + (c2 + (c0 - c1)))
 
-Function name: mcdc_if::mcdc_check_neither
+Function name: if::mcdc_check_neither
 Raw bytes (64): 0x[01, 01, 04, 01, 05, 09, 02, 0d, 0f, 09, 02, 08, 01, 07, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -98,7 +98,7 @@ Number of file 0 mappings: 8
 - Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2)
     = (c3 + (c2 + (c0 - c1)))
 
-Function name: mcdc_if::mcdc_check_not_tree_decision
+Function name: if::mcdc_check_not_tree_decision
 Raw bytes (87): 0x[01, 01, 08, 01, 05, 02, 09, 05, 09, 0d, 1e, 02, 09, 11, 1b, 0d, 1e, 02, 09, 0a, 01, 31, 01, 03, 0a, 28, 00, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 1e, 03, 02, 00, 00, 0e, 00, 0f, 0b, 00, 14, 00, 15, 30, 11, 0d, 02, 00, 00, 00, 14, 00, 15, 11, 00, 16, 02, 06, 1b, 02, 0c, 02, 06, 17, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -133,7 +133,7 @@ Number of file 0 mappings: 10
 - Code(Expression(5, Add)) at (prev + 3, 1) to (start + 0, 2)
     = (c4 + (c3 + ((c0 - c1) - c2)))
 
-Function name: mcdc_if::mcdc_check_tree_decision
+Function name: if::mcdc_check_tree_decision
 Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 0d, 05, 0d, 0d, 11, 09, 02, 1b, 1f, 0d, 11, 09, 02, 0a, 01, 27, 01, 03, 09, 28, 00, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 0d, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 11, 09, 03, 00, 00, 00, 13, 00, 14, 1b, 00, 16, 02, 06, 1f, 02, 0c, 02, 06, 17, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -168,7 +168,7 @@ Number of file 0 mappings: 10
 - Code(Expression(5, Add)) at (prev + 3, 1) to (start + 0, 2)
     = ((c3 + c4) + (c2 + (c0 - c1)))
 
-Function name: mcdc_if::mcdc_nested_if
+Function name: if::mcdc_nested_if
 Raw bytes (124): 0x[01, 01, 0d, 01, 05, 02, 09, 05, 09, 1b, 15, 05, 09, 1b, 15, 05, 09, 11, 15, 02, 09, 2b, 32, 0d, 2f, 11, 15, 02, 09, 0e, 01, 3b, 01, 01, 09, 28, 00, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 32, 02, 00, 00, 00, 0d, 00, 0e, 1b, 01, 09, 01, 0d, 28, 01, 02, 01, 0c, 00, 12, 30, 16, 15, 01, 02, 00, 00, 0c, 00, 0d, 16, 00, 11, 00, 12, 30, 0d, 11, 02, 00, 00, 00, 11, 00, 12, 0d, 00, 13, 02, 0a, 2f, 02, 0a, 00, 0b, 32, 01, 0c, 02, 06, 27, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
diff --git a/tests/coverage/mcdc_if.coverage b/tests/coverage/mcdc/if.coverage
index c2ed311a5bc..91fff073d0c 100644
--- a/tests/coverage/mcdc_if.coverage
+++ b/tests/coverage/mcdc/if.coverage
@@ -2,12 +2,15 @@
    LL|       |//@ edition: 2021
    LL|       |//@ min-llvm-version: 18
    LL|       |//@ compile-flags: -Zcoverage-options=mcdc
-   LL|       |//@ llvm-cov-flags: --show-mcdc
+   LL|       |//@ llvm-cov-flags: --show-branches=count --show-mcdc
    LL|       |
    LL|      2|fn mcdc_check_neither(a: bool, b: bool) {
    LL|      2|    if a && b {
                           ^0
   ------------------
+  |  Branch (LL:8): [True: 0, False: 2]
+  |  Branch (LL:13): [True: 0, False: 0]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:14)
   |
   |  Number of Conditions: 2
@@ -34,6 +37,9 @@
    LL|      2|    if a && b {
                           ^1
   ------------------
+  |  Branch (LL:8): [True: 1, False: 1]
+  |  Branch (LL:13): [True: 1, False: 0]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:14)
   |
   |  Number of Conditions: 2
@@ -60,6 +66,9 @@
    LL|      2|fn mcdc_check_b(a: bool, b: bool) {
    LL|      2|    if a && b {
   ------------------
+  |  Branch (LL:8): [True: 2, False: 0]
+  |  Branch (LL:13): [True: 1, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:14)
   |
   |  Number of Conditions: 2
@@ -87,6 +96,9 @@
    LL|      3|    if a && b {
                           ^2
   ------------------
+  |  Branch (LL:8): [True: 2, False: 1]
+  |  Branch (LL:13): [True: 1, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:14)
   |
   |  Number of Conditions: 2
@@ -117,6 +129,10 @@
    LL|      4|    if a && (b || c) {
                            ^3   ^2
   ------------------
+  |  Branch (LL:8): [True: 3, False: 1]
+  |  Branch (LL:14): [True: 1, False: 2]
+  |  Branch (LL:19): [True: 1, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:21)
   |
   |  Number of Conditions: 3
@@ -150,6 +166,10 @@
    LL|      4|    if (a || b) && c {
                            ^1
   ------------------
+  |  Branch (LL:9): [True: 3, False: 1]
+  |  Branch (LL:14): [True: 1, False: 0]
+  |  Branch (LL:20): [True: 2, False: 2]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:21)
   |
   |  Number of Conditions: 3
@@ -180,6 +200,9 @@
    LL|      3|    if a || b {
                           ^0
   ------------------
+  |  Branch (LL:8): [True: 3, False: 0]
+  |  Branch (LL:13): [True: 0, False: 0]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:14)
   |
   |  Number of Conditions: 2
@@ -200,6 +223,9 @@
    LL|      3|        if b && c {
                               ^2
   ------------------
+  |  Branch (LL:12): [True: 2, False: 1]
+  |  Branch (LL:17): [True: 1, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:12) to (LL:18)
   |
   |  Number of Conditions: 2
diff --git a/tests/coverage/mcdc_if.rs b/tests/coverage/mcdc/if.rs
index a85843721c6..d8e6b61a9d5 100644
--- a/tests/coverage/mcdc_if.rs
+++ b/tests/coverage/mcdc/if.rs
@@ -2,7 +2,7 @@
 //@ edition: 2021
 //@ min-llvm-version: 18
 //@ compile-flags: -Zcoverage-options=mcdc
-//@ llvm-cov-flags: --show-mcdc
+//@ llvm-cov-flags: --show-branches=count --show-mcdc
 
 fn mcdc_check_neither(a: bool, b: bool) {
     if a && b {
diff --git a/tests/coverage/mcdc/inlined_expressions.cov-map b/tests/coverage/mcdc/inlined_expressions.cov-map
new file mode 100644
index 00000000000..09b7291c964
--- /dev/null
+++ b/tests/coverage/mcdc/inlined_expressions.cov-map
@@ -0,0 +1,21 @@
+Function name: inlined_expressions::inlined_instance
+Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 08, 01, 01, 06, 28, 00, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 0d, 02, 00, 00, 00, 0a, 00, 0b, 07, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Expression(2, Add), rhs = Expression(0, Sub)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 8, 1) to (start + 1, 6)
+- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 5) to (start + 0, 11)
+- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 5) to (start + 0, 6)
+    true  = c1
+    false = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 10) to (start + 0, 11)
+- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 10) to (start + 0, 11)
+    true  = c2
+    false = c3
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = ((c2 + c3) + (c0 - c1))
+
diff --git a/tests/coverage/mcdc/inlined_expressions.coverage b/tests/coverage/mcdc/inlined_expressions.coverage
new file mode 100644
index 00000000000..5b083d62186
--- /dev/null
+++ b/tests/coverage/mcdc/inlined_expressions.coverage
@@ -0,0 +1,41 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |//@ min-llvm-version: 18
+   LL|       |//@ compile-flags: -Zcoverage-options=mcdc -Copt-level=z -Cllvm-args=--inline-threshold=0
+   LL|       |//@ llvm-cov-flags: --show-branches=count --show-mcdc
+   LL|       |
+   LL|       |#[inline(always)]
+   LL|      3|fn inlined_instance(a: bool, b: bool) -> bool {
+   LL|      3|    a && b
+                       ^2
+  ------------------
+  |  Branch (LL:5): [True: 2, False: 1]
+  |  Branch (LL:10): [True: 1, False: 1]
+  ------------------
+  |---> MC/DC Decision Region (LL:5) to (LL:11)
+  |
+  |  Number of Conditions: 2
+  |     Condition C1 --> (LL:5)
+  |     Condition C2 --> (LL:10)
+  |
+  |  Executed MC/DC Test Vectors:
+  |
+  |     C1, C2    Result
+  |  1 { F,  -  = F      }
+  |  2 { T,  F  = F      }
+  |  3 { T,  T  = T      }
+  |
+  |  C1-Pair: covered: (1,3)
+  |  C2-Pair: covered: (2,3)
+  |  MC/DC Coverage for Decision: 100.00%
+  |
+  ------------------
+   LL|      3|}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    let _ = inlined_instance(true, false);
+   LL|       |    let _ = inlined_instance(false, true);
+   LL|       |    let _ = inlined_instance(true, true);
+   LL|       |}
+
diff --git a/tests/coverage/mcdc/inlined_expressions.rs b/tests/coverage/mcdc/inlined_expressions.rs
new file mode 100644
index 00000000000..65f7ee66f39
--- /dev/null
+++ b/tests/coverage/mcdc/inlined_expressions.rs
@@ -0,0 +1,17 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+//@ min-llvm-version: 18
+//@ compile-flags: -Zcoverage-options=mcdc -Copt-level=z -Cllvm-args=--inline-threshold=0
+//@ llvm-cov-flags: --show-branches=count --show-mcdc
+
+#[inline(always)]
+fn inlined_instance(a: bool, b: bool) -> bool {
+    a && b
+}
+
+#[coverage(off)]
+fn main() {
+    let _ = inlined_instance(true, false);
+    let _ = inlined_instance(false, true);
+    let _ = inlined_instance(true, true);
+}
diff --git a/tests/coverage/mcdc_nested_if.cov-map b/tests/coverage/mcdc/nested_if.cov-map
index 2f35ffad8a9..adeb6cbc1fb 100644
--- a/tests/coverage/mcdc_nested_if.cov-map
+++ b/tests/coverage/mcdc/nested_if.cov-map
@@ -1,4 +1,4 @@
-Function name: mcdc_nested_if::doubly_nested_if_in_condition
+Function name: nested_if::doubly_nested_if_in_condition
 Raw bytes (168): 0x[01, 01, 0e, 01, 05, 05, 11, 05, 11, 26, 19, 05, 11, 19, 1d, 19, 1d, 1d, 22, 26, 19, 05, 11, 11, 15, 09, 02, 0d, 37, 09, 02, 14, 01, 0f, 01, 01, 09, 28, 02, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 01, 02, 00, 10, 00, 36, 30, 11, 26, 01, 00, 02, 00, 10, 00, 11, 30, 15, 21, 02, 00, 00, 00, 15, 00, 36, 26, 00, 18, 00, 19, 28, 00, 02, 00, 18, 00, 1e, 30, 19, 22, 01, 02, 00, 00, 18, 00, 19, 19, 00, 1d, 00, 1e, 30, 1a, 1d, 02, 00, 00, 00, 1d, 00, 1e, 1a, 00, 21, 00, 25, 1f, 00, 2f, 00, 34, 2b, 00, 39, 00, 3e, 21, 00, 48, 00, 4c, 0d, 00, 4f, 02, 06, 37, 02, 0c, 02, 06, 33, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -57,7 +57,7 @@ Number of file 0 mappings: 20
 - Code(Expression(12, Add)) at (prev + 3, 1) to (start + 0, 2)
     = (c3 + (c2 + (c0 - c1)))
 
-Function name: mcdc_nested_if::nested_if_in_condition
+Function name: nested_if::nested_if_in_condition
 Raw bytes (120): 0x[01, 01, 0b, 01, 05, 05, 11, 05, 11, 1e, 15, 05, 11, 11, 15, 1e, 15, 05, 11, 09, 02, 0d, 2b, 09, 02, 0e, 01, 07, 01, 01, 09, 28, 01, 02, 01, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 00, 02, 00, 10, 00, 16, 30, 11, 1e, 01, 00, 02, 00, 10, 00, 11, 1e, 00, 15, 00, 16, 30, 15, 1a, 02, 00, 00, 00, 15, 00, 16, 17, 00, 19, 00, 1d, 1a, 00, 27, 00, 2c, 0d, 00, 2f, 02, 06, 2b, 02, 0c, 02, 06, 27, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -102,7 +102,7 @@ Number of file 0 mappings: 14
 - Code(Expression(9, Add)) at (prev + 3, 1) to (start + 0, 2)
     = (c3 + (c2 + (c0 - c1)))
 
-Function name: mcdc_nested_if::nested_in_then_block_in_condition
+Function name: nested_if::nested_in_then_block_in_condition
 Raw bytes (176): 0x[01, 01, 12, 01, 05, 05, 11, 05, 11, 3a, 15, 05, 11, 11, 15, 33, 19, 11, 15, 19, 1d, 19, 1d, 1d, 2e, 33, 19, 11, 15, 3a, 15, 05, 11, 09, 02, 0d, 47, 09, 02, 14, 01, 22, 01, 01, 09, 28, 02, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 00, 02, 00, 10, 00, 16, 30, 11, 3a, 01, 00, 02, 00, 10, 00, 11, 3a, 00, 15, 00, 16, 30, 15, 36, 02, 00, 00, 00, 15, 00, 16, 33, 00, 1c, 00, 1d, 28, 01, 02, 00, 1c, 00, 22, 30, 19, 2e, 01, 02, 00, 00, 1c, 00, 1d, 19, 00, 21, 00, 22, 30, 26, 1d, 02, 00, 00, 00, 21, 00, 22, 26, 00, 25, 00, 29, 2b, 00, 33, 00, 38, 36, 00, 44, 00, 49, 0d, 00, 4c, 02, 06, 47, 02, 0c, 02, 06, 43, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -166,7 +166,7 @@ Number of file 0 mappings: 20
 - Code(Expression(16, Add)) at (prev + 3, 1) to (start + 0, 2)
     = (c3 + (c2 + (c0 - c1)))
 
-Function name: mcdc_nested_if::nested_single_condition_decision
+Function name: nested_if::nested_single_condition_decision
 Raw bytes (85): 0x[01, 01, 06, 01, 05, 05, 11, 05, 11, 09, 02, 0d, 17, 09, 02, 0b, 01, 17, 01, 04, 09, 28, 00, 02, 04, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 09, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 11, 0a, 00, 10, 00, 11, 11, 00, 14, 00, 19, 0a, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 17, 02, 0c, 02, 06, 13, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
diff --git a/tests/coverage/mcdc_nested_if.coverage b/tests/coverage/mcdc/nested_if.coverage
index 19529cd6aa4..a273a713a8a 100644
--- a/tests/coverage/mcdc_nested_if.coverage
+++ b/tests/coverage/mcdc/nested_if.coverage
@@ -2,12 +2,17 @@
    LL|       |//@ edition: 2021
    LL|       |//@ min-llvm-version: 18
    LL|       |//@ compile-flags: -Zcoverage-options=mcdc
-   LL|       |//@ llvm-cov-flags: --show-mcdc
+   LL|       |//@ llvm-cov-flags: --show-branches=count --show-mcdc
    LL|       |
    LL|      4|fn nested_if_in_condition(a: bool, b: bool, c: bool) {
    LL|      4|    if a && if b || c { true } else { false } {
                              ^3   ^2  ^2            ^1
   ------------------
+  |  Branch (LL:8): [True: 3, False: 1]
+  |  Branch (LL:13): [True: 2, False: 1]
+  |  Branch (LL:16): [True: 1, False: 2]
+  |  Branch (LL:21): [True: 1, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:46)
   |
   |  Number of Conditions: 2
@@ -53,6 +58,13 @@
    LL|      4|    if a && if b || if c && d { true } else { false } { false } else { true } {
                              ^3      ^2   ^1  ^1            ^1        ^2             ^1
   ------------------
+  |  Branch (LL:8): [True: 3, False: 1]
+  |  Branch (LL:13): [True: 1, False: 2]
+  |  Branch (LL:16): [True: 1, False: 2]
+  |  Branch (LL:21): [True: 1, False: 1]
+  |  Branch (LL:24): [True: 1, False: 1]
+  |  Branch (LL:29): [True: 1, False: 0]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:78)
   |
   |  Number of Conditions: 2
@@ -117,6 +129,10 @@
    LL|      3|    if a && if b { false } else { true } {
                              ^2  ^1             ^1
   ------------------
+  |  Branch (LL:8): [True: 2, False: 1]
+  |  Branch (LL:13): [True: 1, False: 1]
+  |  Branch (LL:16): [True: 1, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:41)
   |
   |  Number of Conditions: 2
@@ -145,6 +161,13 @@
    LL|      7|    if a && if b || c { if d && e { true } else { false } } else { false } {
                              ^6   ^5     ^5   ^2  ^1            ^4               ^1
   ------------------
+  |  Branch (LL:8): [True: 6, False: 1]
+  |  Branch (LL:13): [True: 1, False: 5]
+  |  Branch (LL:16): [True: 1, False: 5]
+  |  Branch (LL:21): [True: 4, False: 1]
+  |  Branch (LL:28): [True: 2, False: 3]
+  |  Branch (LL:33): [True: 1, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:8) to (LL:75)
   |
   |  Number of Conditions: 2
diff --git a/tests/coverage/mcdc_nested_if.rs b/tests/coverage/mcdc/nested_if.rs
index 3d869771f75..f5068b5dcc2 100644
--- a/tests/coverage/mcdc_nested_if.rs
+++ b/tests/coverage/mcdc/nested_if.rs
@@ -2,7 +2,7 @@
 //@ edition: 2021
 //@ min-llvm-version: 18
 //@ compile-flags: -Zcoverage-options=mcdc
-//@ llvm-cov-flags: --show-mcdc
+//@ llvm-cov-flags: --show-branches=count --show-mcdc
 
 fn nested_if_in_condition(a: bool, b: bool, c: bool) {
     if a && if b || c { true } else { false } {
diff --git a/tests/coverage/mcdc_non_control_flow.cov-map b/tests/coverage/mcdc/non_control_flow.cov-map
index 937c36e1f16..f8576831e75 100644
--- a/tests/coverage/mcdc_non_control_flow.cov-map
+++ b/tests/coverage/mcdc/non_control_flow.cov-map
@@ -1,4 +1,4 @@
-Function name: mcdc_non_control_flow::assign_3
+Function name: non_control_flow::assign_3
 Raw bytes (89): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 0a, 01, 16, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 22, 01, 00, 02, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 30, 1e, 11, 02, 03, 00, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 30, 09, 0d, 03, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -34,7 +34,7 @@ Number of file 0 mappings: 10
 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
     = (c1 + ((c2 + c3) + c4))
 
-Function name: mcdc_non_control_flow::assign_3_bis
+Function name: non_control_flow::assign_3_bis
 Raw bytes (85): 0x[01, 01, 07, 07, 11, 09, 0d, 01, 05, 05, 09, 16, 1a, 05, 09, 01, 05, 0a, 01, 1b, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 1a, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 16, 03, 00, 02, 00, 12, 00, 13, 13, 00, 17, 00, 18, 30, 0d, 11, 02, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -67,7 +67,7 @@ Number of file 0 mappings: 10
 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
     = ((c2 + c3) + c4)
 
-Function name: mcdc_non_control_flow::assign_and
+Function name: non_control_flow::assign_and
 Raw bytes (64): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 08, 01, 0c, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -92,7 +92,7 @@ Number of file 0 mappings: 8
 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
     = ((c2 + c3) + (c0 - c1))
 
-Function name: mcdc_non_control_flow::assign_or
+Function name: non_control_flow::assign_or
 Raw bytes (64): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 08, 01, 11, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 00, 02, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -118,7 +118,7 @@ Number of file 0 mappings: 8
 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
     = ((c1 + c2) + c3)
 
-Function name: mcdc_non_control_flow::foo
+Function name: non_control_flow::foo
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 02, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -126,7 +126,7 @@ Number of expressions: 0
 Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 37, 1) to (start + 2, 2)
 
-Function name: mcdc_non_control_flow::func_call
+Function name: non_control_flow::func_call
 Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 29, 01, 01, 0a, 28, 00, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 0d, 02, 00, 00, 00, 0e, 00, 0f, 07, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
@@ -147,7 +147,7 @@ Number of file 0 mappings: 6
 - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
     = ((c2 + c3) + (c0 - c1))
 
-Function name: mcdc_non_control_flow::right_comb_tree
+Function name: non_control_flow::right_comb_tree
 Raw bytes (139): 0x[01, 01, 13, 07, 1a, 0b, 19, 0f, 15, 13, 11, 09, 0d, 01, 05, 01, 05, 05, 19, 05, 19, 4a, 15, 05, 19, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 0e, 01, 20, 01, 00, 41, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 05, 00, 0d, 00, 2a, 30, 05, 1a, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 4a, 19, 02, 03, 00, 00, 13, 00, 14, 4a, 00, 19, 00, 1a, 30, 46, 15, 03, 04, 00, 00, 19, 00, 1a, 46, 00, 1f, 00, 20, 30, 42, 11, 04, 05, 00, 00, 1f, 00, 20, 42, 00, 24, 00, 27, 30, 09, 0d, 05, 00, 00, 00, 24, 00, 27, 03, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
diff --git a/tests/coverage/mcdc_non_control_flow.coverage b/tests/coverage/mcdc/non_control_flow.coverage
index cd733885a98..6ae796e8ed2 100644
--- a/tests/coverage/mcdc_non_control_flow.coverage
+++ b/tests/coverage/mcdc/non_control_flow.coverage
@@ -2,7 +2,7 @@
    LL|       |//@ edition: 2021
    LL|       |//@ min-llvm-version: 18
    LL|       |//@ compile-flags: -Zcoverage-options=mcdc
-   LL|       |//@ llvm-cov-flags: --show-mcdc
+   LL|       |//@ llvm-cov-flags: --show-branches=count --show-mcdc
    LL|       |
    LL|       |// This test ensures that boolean expressions that are not inside control flow
    LL|       |// decisions are correctly instrumented.
@@ -13,6 +13,9 @@
    LL|      3|    let x = a && b;
                                ^2
   ------------------
+  |  Branch (LL:13): [True: 2, False: 1]
+  |  Branch (LL:18): [True: 1, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:13) to (LL:19)
   |
   |  Number of Conditions: 2
@@ -38,6 +41,9 @@
    LL|      3|    let x = a || b;
                                ^1
   ------------------
+  |  Branch (LL:13): [True: 2, False: 1]
+  |  Branch (LL:18): [True: 0, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:13) to (LL:19)
   |
   |  Number of Conditions: 2
@@ -62,6 +68,10 @@
    LL|      4|    let x = a || b && c;
                                ^2   ^1
   ------------------
+  |  Branch (LL:13): [True: 2, False: 2]
+  |  Branch (LL:18): [True: 1, False: 1]
+  |  Branch (LL:23): [True: 1, False: 0]
+  ------------------
   |---> MC/DC Decision Region (LL:13) to (LL:24)
   |
   |  Number of Conditions: 3
@@ -89,6 +99,10 @@
    LL|      4|    let x = a && b || c;
                                ^2   ^3
   ------------------
+  |  Branch (LL:13): [True: 2, False: 2]
+  |  Branch (LL:18): [True: 1, False: 1]
+  |  Branch (LL:23): [True: 2, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:13) to (LL:24)
   |
   |  Number of Conditions: 3
@@ -116,6 +130,12 @@
    LL|      3|    let x = a && (b && (c && (d && (e))));
                                 ^2    ^1    ^1   ^1
   ------------------
+  |  Branch (LL:13): [True: 2, False: 1]
+  |  Branch (LL:19): [True: 1, False: 1]
+  |  Branch (LL:25): [True: 1, False: 0]
+  |  Branch (LL:31): [True: 1, False: 0]
+  |  Branch (LL:36): [True: 1, False: 0]
+  ------------------
   |---> MC/DC Decision Region (LL:13) to (LL:42)
   |
   |  Number of Conditions: 5
@@ -151,6 +171,9 @@
    LL|      3|    foo(a && b);
                            ^2
   ------------------
+  |  Branch (LL:9): [True: 2, False: 1]
+  |  Branch (LL:14): [True: 1, False: 1]
+  ------------------
   |---> MC/DC Decision Region (LL:9) to (LL:15)
   |
   |  Number of Conditions: 2
diff --git a/tests/coverage/mcdc_non_control_flow.rs b/tests/coverage/mcdc/non_control_flow.rs
index 85c0a6c6ae5..77e64e6625b 100644
--- a/tests/coverage/mcdc_non_control_flow.rs
+++ b/tests/coverage/mcdc/non_control_flow.rs
@@ -2,7 +2,7 @@
 //@ edition: 2021
 //@ min-llvm-version: 18
 //@ compile-flags: -Zcoverage-options=mcdc
-//@ llvm-cov-flags: --show-mcdc
+//@ llvm-cov-flags: --show-branches=count --show-mcdc
 
 // This test ensures that boolean expressions that are not inside control flow
 // decisions are correctly instrumented.
diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map
index 281efb6d00d..75234f6c3b7 100644
--- a/tests/coverage/no_cov_crate.cov-map
+++ b/tests/coverage/no_cov_crate.cov-map
@@ -31,20 +31,22 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 77, 1) to (start + 11, 2)
 
 Function name: no_cov_crate::nested_fns::outer
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 05, 0c, 06]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 31, 05, 02, 23, 01, 0c, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 49, 5) to (start + 12, 6)
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 49, 5) to (start + 2, 35)
+- Code(Counter(0)) at (prev + 12, 5) to (start + 0, 6)
 
 Function name: no_cov_crate::nested_fns::outer_both_covered
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 3f, 05, 0b, 06]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 3f, 05, 02, 17, 01, 0b, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 63, 5) to (start + 11, 6)
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 63, 5) to (start + 2, 23)
+- Code(Counter(0)) at (prev + 11, 5) to (start + 0, 6)
 
 Function name: no_cov_crate::nested_fns::outer_both_covered::inner
 Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
diff --git a/tests/coverage/no_cov_crate.coverage b/tests/coverage/no_cov_crate.coverage
index 29ad1f979cf..6a43e52652e 100644
--- a/tests/coverage/no_cov_crate.coverage
+++ b/tests/coverage/no_cov_crate.coverage
@@ -49,21 +49,21 @@
    LL|      1|    pub fn outer(is_true: bool) {
    LL|      1|        println!("called and covered");
    LL|      1|        inner_not_covered(is_true);
-   LL|      1|
-   LL|      1|        #[coverage(off)]
-   LL|      1|        fn inner_not_covered(is_true: bool) {
-   LL|      1|            if is_true {
-   LL|      1|                println!("called but not covered");
-   LL|      1|            } else {
-   LL|      1|                println!("absolutely not covered");
-   LL|      1|            }
-   LL|      1|        }
+   LL|       |
+   LL|       |        #[coverage(off)]
+   LL|       |        fn inner_not_covered(is_true: bool) {
+   LL|       |            if is_true {
+   LL|       |                println!("called but not covered");
+   LL|       |            } else {
+   LL|       |                println!("absolutely not covered");
+   LL|       |            }
+   LL|       |        }
    LL|      1|    }
    LL|       |
    LL|      1|    pub fn outer_both_covered(is_true: bool) {
    LL|      1|        println!("called and covered");
    LL|      1|        inner(is_true);
-   LL|      1|
+   LL|       |
    LL|      1|        fn inner(is_true: bool) {
    LL|      1|            if is_true {
    LL|      1|                println!("called and covered");
diff --git a/tests/crashes/125099.rs b/tests/crashes/125099.rs
deleted file mode 100644
index bfc8c8fdcf6..00000000000
--- a/tests/crashes/125099.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-//@ known-bug: rust-lang/rust#125099
-
-pub trait ContFn<T>: Fn(T) -> Self::Future {
-    type Future;
-}
-impl<T, F> ContFn<T> for F
-where
-    F: Fn(T),
-{
-    type Future = ();
-}
-
-pub trait SeqHandler {
-    type Requires;
-    fn process<F: ContFn<Self::Requires>>() -> impl Sized;
-}
-
-pub struct ConvertToU64;
-impl SeqHandler for ConvertToU64 {
-    type Requires = u64;
-    fn process<F: ContFn<Self::Requires>>() -> impl Sized {}
-}
-
-fn main() {}
diff --git a/tests/crashes/125249.rs b/tests/crashes/125249.rs
index 18196d7b34f..1cf6338a0d6 100644
--- a/tests/crashes/125249.rs
+++ b/tests/crashes/125249.rs
@@ -2,7 +2,7 @@
 #![feature(return_position_impl_trait_in_trait, return_type_notation)]
 
 trait IntFactory {
-    fn stream(&self) -> impl IntFactory<stream(): IntFactory<stream(): Send> + Send>;
+    fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>;
 }
 
 pub fn main() {}
diff --git a/tests/crashes/126896.rs b/tests/crashes/126896.rs
new file mode 100644
index 00000000000..35bf9d5207a
--- /dev/null
+++ b/tests/crashes/126896.rs
@@ -0,0 +1,17 @@
+//@ known-bug: rust-lang/rust#126896
+//@ compile-flags: -Zpolymorphize=on -Zinline-mir=yes
+
+#![feature(type_alias_impl_trait)]
+type Two<'a, 'b> = impl std::fmt::Debug;
+
+fn set(x: &mut isize) -> isize {
+    *x
+}
+
+fn d(x: Two) {
+    let c1 = || set(x);
+    c1;
+}
+
+fn main() {
+}
diff --git a/tests/crashes/126939.rs b/tests/crashes/126939.rs
new file mode 100644
index 00000000000..1edf7484606
--- /dev/null
+++ b/tests/crashes/126939.rs
@@ -0,0 +1,21 @@
+//@ known-bug: rust-lang/rust#126939
+
+struct MySlice<T: Copy>(bool, T);
+type MySliceBool = MySlice<[bool]>;
+
+use std::mem;
+
+struct P2<T> {
+    a: T,
+    b: MySliceBool,
+}
+
+macro_rules! check {
+    ($t:ty, $align:expr) => ({
+        assert_eq!(mem::align_of::<$t>(), $align);
+    });
+}
+
+pub fn main() {
+    check!(P2<u8>, 1);
+}
diff --git a/tests/crashes/126942.rs b/tests/crashes/126942.rs
new file mode 100644
index 00000000000..e4adc8fab28
--- /dev/null
+++ b/tests/crashes/126942.rs
@@ -0,0 +1,11 @@
+//@ known-bug: rust-lang/rust#126942
+struct Thing;
+
+pub trait Every {
+    type Assoc;
+}
+impl<T: ?Sized> Every for Thing {
+    type Assoc = T;
+}
+
+static I: <Thing as Every>::Assoc = 3;
diff --git a/tests/crashes/126944.rs b/tests/crashes/126944.rs
new file mode 100644
index 00000000000..c0c5622e260
--- /dev/null
+++ b/tests/crashes/126944.rs
@@ -0,0 +1,38 @@
+//@ known-bug: rust-lang/rust#126944
+// Step 1: Create two names for a single type: `Thing` and `AlsoThing`
+
+struct Thing;
+struct Dummy;
+pub trait DummyTrait {
+    type DummyType;
+}
+impl DummyTrait for Dummy {
+    type DummyType = Thing;
+}
+type AlsoThing = <Dummy as DummyTrait>::DummyType;
+
+// Step 2: Create names for a single trait object type: `TraitObject` and `AlsoTraitObject`
+
+pub trait SomeTrait {
+    type Item;
+}
+type TraitObject = dyn SomeTrait<Item = AlsoThing>;
+type AlsoTraitObject = dyn SomeTrait<Item = Thing>;
+
+// Step 3: Force the compiler to check whether the two names are the same type
+
+pub trait Supertrait {
+    type Foo;
+}
+pub trait Subtrait: Supertrait<Foo = TraitObject> {}
+
+pub trait HasOutput<A: ?Sized> {
+    type Output;
+}
+
+fn foo<F>() -> F::Output
+where
+    F: HasOutput<dyn Subtrait<Foo = AlsoTraitObject>>,
+{
+    todo!()
+}
diff --git a/tests/crashes/126966.rs b/tests/crashes/126966.rs
new file mode 100644
index 00000000000..edeedc68c40
--- /dev/null
+++ b/tests/crashes/126966.rs
@@ -0,0 +1,29 @@
+//@ known-bug: rust-lang/rust#126966
+mod assert {
+    use std::mem::{Assume, BikeshedIntrinsicFrom};
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src>,
+    {
+    }
+}
+
+#[repr(u32)]
+enum Ox00 {
+    V = 0x00,
+}
+
+#[repr(C, packed(2))]
+enum OxFF {
+    V = 0xFF,
+}
+
+fn test() {
+    union Superset {
+        a: Ox00,
+        b: OxFF,
+    }
+
+    assert::is_transmutable::<Superset, Subset>();
+}
diff --git a/tests/crashes/126969.rs b/tests/crashes/126969.rs
new file mode 100644
index 00000000000..676563d059c
--- /dev/null
+++ b/tests/crashes/126969.rs
@@ -0,0 +1,9 @@
+//@ known-bug: rust-lang/rust#126969
+
+struct S<T> {
+    _: union { t: T },
+}
+
+fn f(S::<&i8> { .. }: S<&i8>) {}
+
+fn main() {}
diff --git a/tests/crashes/126982.rs b/tests/crashes/126982.rs
new file mode 100644
index 00000000000..8522d9415eb
--- /dev/null
+++ b/tests/crashes/126982.rs
@@ -0,0 +1,18 @@
+//@ known-bug: rust-lang/rust#126982
+
+#![feature(coerce_unsized)]
+use std::ops::CoerceUnsized;
+
+struct Foo<T: ?Sized> {
+    a: T,
+}
+
+impl<T, U> CoerceUnsized<U> for Foo<T> {}
+
+union U {
+    a: usize,
+}
+
+const C: U = Foo { a: 10 };
+
+fn main() {}
diff --git a/tests/crashes/127222.rs b/tests/crashes/127222.rs
new file mode 100644
index 00000000000..eda0ea3d9b7
--- /dev/null
+++ b/tests/crashes/127222.rs
@@ -0,0 +1,3 @@
+//@ known-bug: rust-lang/rust#127222
+#[marker]
+trait Foo = PartialEq<i32> + Send;
diff --git a/tests/crashes/127266.rs b/tests/crashes/127266.rs
new file mode 100644
index 00000000000..2bdbe03e373
--- /dev/null
+++ b/tests/crashes/127266.rs
@@ -0,0 +1,17 @@
+//@ known-bug: rust-lang/rust#127266
+#![feature(const_mut_refs)]
+#![feature(const_refs_to_static)]
+
+struct Meh {
+    x: &'static dyn UnsafeCell,
+}
+
+const MUH: Meh = Meh {
+    x: &mut *(READONLY as *mut _),
+};
+
+static READONLY: i32 = 0;
+
+trait UnsafeCell<'a> {}
+
+pub fn main() {}
diff --git a/tests/crashes/127299.rs b/tests/crashes/127299.rs
new file mode 100644
index 00000000000..7eb78387997
--- /dev/null
+++ b/tests/crashes/127299.rs
@@ -0,0 +1,12 @@
+//@ known-bug: rust-lang/rust#127299
+trait Qux {
+    fn bar() -> i32;
+}
+
+pub struct Lint {
+    pub desc: &'static Qux,
+}
+
+static FOO: &Lint = &Lint { desc: "desc" };
+
+fn main() {}
diff --git a/tests/crashes/127304.rs b/tests/crashes/127304.rs
new file mode 100644
index 00000000000..2975fc27f67
--- /dev/null
+++ b/tests/crashes/127304.rs
@@ -0,0 +1,20 @@
+//@ known-bug: rust-lang/rust #127304
+#![feature(adt_const_params)]
+
+trait Trait<T> {}
+impl Trait<u16> for () {}
+
+struct MyStr(str);
+impl std::marker::ConstParamTy for MyStr {}
+
+fn function_with_my_str<const S: &'static MyStr>() -> &'static MyStr {
+    S
+}
+
+impl MyStr {
+    const fn new(s: &Trait str) -> &'static MyStr {}
+}
+
+pub fn main() {
+    let f = function_with_my_str::<{ MyStr::new("hello") }>();
+}
diff --git a/tests/debuginfo/basic-types-globals-metadata.rs b/tests/debuginfo/basic-types-globals-metadata.rs
index 124be655c35..d346b405555 100644
--- a/tests/debuginfo/basic-types-globals-metadata.rs
+++ b/tests/debuginfo/basic-types-globals-metadata.rs
@@ -39,6 +39,9 @@
 // gdbg-command:whatis 'basic_types_globals_metadata::U64'
 // gdbr-command:whatis basic_types_globals_metadata::U64
 // gdb-check:type = u64
+// gdbg-command:whatis 'basic_types_globals_metadata::F16'
+// gdbr-command:whatis basic_types_globals_metadata::F16
+// gdb-check:type = f16
 // gdbg-command:whatis 'basic_types_globals_metadata::F32'
 // gdbr-command:whatis basic_types_globals_metadata::F32
 // gdb-check:type = f32
@@ -51,6 +54,7 @@
 #![allow(dead_code)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
+#![feature(f16)]
 
 // N.B. These are `mut` only so they don't constant fold away.
 static mut B: bool = false;
@@ -65,13 +69,14 @@ static mut U8: u8 = 100;
 static mut U16: u16 = 16;
 static mut U32: u32 = 32;
 static mut U64: u64 = 64;
+static mut F16: f16 = 1.5;
 static mut F32: f32 = 2.5;
 static mut F64: f64 = 3.5;
 
 fn main() {
     _zzz(); // #break
 
-    let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) };
+    let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F16, F32, F64) };
 }
 
 fn _zzz() {()}
diff --git a/tests/debuginfo/basic-types-globals.rs b/tests/debuginfo/basic-types-globals.rs
index 319e86ad460..0425d14fa5a 100644
--- a/tests/debuginfo/basic-types-globals.rs
+++ b/tests/debuginfo/basic-types-globals.rs
@@ -49,17 +49,21 @@
 // gdbg-command:print 'basic_types_globals::U64'
 // gdbr-command:print U64
 // gdb-check:$12 = 64
+// gdbg-command:print 'basic_types_globals::F16'
+// gdbr-command:print F16
+// gdb-check:$13 = 1.5
 // gdbg-command:print 'basic_types_globals::F32'
 // gdbr-command:print F32
-// gdb-check:$13 = 2.5
+// gdb-check:$14 = 2.5
 // gdbg-command:print 'basic_types_globals::F64'
 // gdbr-command:print F64
-// gdb-check:$14 = 3.5
+// gdb-check:$15 = 3.5
 // gdb-command:continue
 
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
+#![feature(f16)]
 
 // N.B. These are `mut` only so they don't constant fold away.
 static mut B: bool = false;
@@ -74,13 +78,14 @@ static mut U8: u8 = 100;
 static mut U16: u16 = 16;
 static mut U32: u32 = 32;
 static mut U64: u64 = 64;
+static mut F16: f16 = 1.5;
 static mut F32: f32 = 2.5;
 static mut F64: f64 = 3.5;
 
 fn main() {
     _zzz(); // #break
 
-    let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) };
+    let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F16, F32, F64) };
 }
 
 fn _zzz() {()}
diff --git a/tests/debuginfo/basic-types-metadata.rs b/tests/debuginfo/basic-types-metadata.rs
index 8a25c0c4524..5f953c81a13 100644
--- a/tests/debuginfo/basic-types-metadata.rs
+++ b/tests/debuginfo/basic-types-metadata.rs
@@ -29,6 +29,8 @@
 // gdb-check:type = u32
 // gdb-command:whatis u64
 // gdb-check:type = u64
+// gdb-command:whatis f16
+// gdb-check:type = f16
 // gdb-command:whatis f32
 // gdb-check:type = f32
 // gdb-command:whatis f64
@@ -66,6 +68,7 @@
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
+#![feature(f16)]
 
 fn main() {
     let unit: () = ();
@@ -81,6 +84,7 @@ fn main() {
     let u16: u16 = 16;
     let u32: u32 = 32;
     let u64: u64 = 64;
+    let f16: f16 = 1.5;
     let f32: f32 = 2.5;
     let f64: f64 = 3.5;
     let fnptr : fn() = _zzz;
diff --git a/tests/debuginfo/basic-types-mut-globals.rs b/tests/debuginfo/basic-types-mut-globals.rs
index c3e5f2534d3..c676fd73771 100644
--- a/tests/debuginfo/basic-types-mut-globals.rs
+++ b/tests/debuginfo/basic-types-mut-globals.rs
@@ -5,7 +5,6 @@
 // its numerical value.
 
 //@ min-lldb-version: 310
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
 
 //@ compile-flags:-g
 
@@ -49,62 +48,69 @@
 // gdbg-command:print 'basic_types_mut_globals::U64'
 // gdbr-command:print U64
 // gdb-check:$12 = 64
+// gdbg-command:print 'basic_types_mut_globals::F16'
+// gdbr-command:print F16
+// gdb-check:$13 = 1.5
 // gdbg-command:print 'basic_types_mut_globals::F32'
 // gdbr-command:print F32
-// gdb-check:$13 = 2.5
+// gdb-check:$14 = 2.5
 // gdbg-command:print 'basic_types_mut_globals::F64'
 // gdbr-command:print F64
-// gdb-check:$14 = 3.5
+// gdb-check:$15 = 3.5
 // gdb-command:continue
 
 // Check new values
 // gdbg-command:print 'basic_types_mut_globals'::B
 // gdbr-command:print B
-// gdb-check:$15 = true
+// gdb-check:$16 = true
 // gdbg-command:print 'basic_types_mut_globals'::I
 // gdbr-command:print I
-// gdb-check:$16 = 2
+// gdb-check:$17 = 2
 // gdbg-command:print/d 'basic_types_mut_globals'::C
 // gdbr-command:print C
-// gdbg-check:$17 = 102
-// gdbr-check:$17 = 102 'f'
+// gdbg-check:$18 = 102
+// gdbr-check:$18 = 102 'f'
 // gdbg-command:print/d 'basic_types_mut_globals'::I8
 // gdbr-command:print/d I8
-// gdb-check:$18 = 78
+// gdb-check:$19 = 78
 // gdbg-command:print 'basic_types_mut_globals'::I16
 // gdbr-command:print I16
-// gdb-check:$19 = -26
+// gdb-check:$20 = -26
 // gdbg-command:print 'basic_types_mut_globals'::I32
 // gdbr-command:print I32
-// gdb-check:$20 = -12
+// gdb-check:$21 = -12
 // gdbg-command:print 'basic_types_mut_globals'::I64
 // gdbr-command:print I64
-// gdb-check:$21 = -54
+// gdb-check:$22 = -54
 // gdbg-command:print 'basic_types_mut_globals'::U
 // gdbr-command:print U
-// gdb-check:$22 = 5
+// gdb-check:$23 = 5
 // gdbg-command:print/d 'basic_types_mut_globals'::U8
 // gdbr-command:print/d U8
-// gdb-check:$23 = 20
+// gdb-check:$24 = 20
 // gdbg-command:print 'basic_types_mut_globals'::U16
 // gdbr-command:print U16
-// gdb-check:$24 = 32
+// gdb-check:$25 = 32
 // gdbg-command:print 'basic_types_mut_globals'::U32
 // gdbr-command:print U32
-// gdb-check:$25 = 16
+// gdb-check:$26 = 16
 // gdbg-command:print 'basic_types_mut_globals'::U64
 // gdbr-command:print U64
-// gdb-check:$26 = 128
+// gdb-check:$27 = 128
+// gdbg-command:print 'basic_types_mut_globals'::F16
+// gdbr-command:print F16
+// gdb-check:$28 = 2.25
 // gdbg-command:print 'basic_types_mut_globals'::F32
 // gdbr-command:print F32
-// gdb-check:$27 = 5.75
+// gdb-check:$29 = 5.75
 // gdbg-command:print 'basic_types_mut_globals'::F64
 // gdbr-command:print F64
-// gdb-check:$28 = 9.25
+// gdb-check:$30 = 9.25
 
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
+#![feature(f16)]
 
 static mut B: bool = false;
 static mut I: isize = -1;
@@ -118,6 +124,7 @@ static mut U8: u8 = 100;
 static mut U16: u16 = 16;
 static mut U32: u32 = 32;
 static mut U64: u64 = 64;
+static mut F16: f16 = 1.5;
 static mut F32: f32 = 2.5;
 static mut F64: f64 = 3.5;
 
@@ -137,6 +144,7 @@ fn main() {
         U16 = 32;
         U32 = 16;
         U64 = 128;
+        F16 = 2.25;
         F32 = 5.75;
         F64 = 9.25;
     }
diff --git a/tests/debuginfo/basic-types.rs b/tests/debuginfo/basic-types.rs
index 13d85d326ee..10ffd74d3e9 100644
--- a/tests/debuginfo/basic-types.rs
+++ b/tests/debuginfo/basic-types.rs
@@ -39,13 +39,15 @@
 // gdb-check:$11 = 32
 // gdb-command:print u64
 // gdb-check:$12 = 64
+// gdb-command:print f16
+// gdb-check:$13 = 1.5
 // gdb-command:print f32
-// gdb-check:$13 = 2.5
+// gdb-check:$14 = 2.5
 // gdb-command:print f64
-// gdb-check:$14 = 3.5
+// gdb-check:$15 = 3.5
 // gdb-command:print s
-// gdbg-check:$15 = {data_ptr = [...] "Hello, World!", length = 13}
-// gdbr-check:$15 = "Hello, World!"
+// gdbg-check:$16 = {data_ptr = [...] "Hello, World!", length = 13}
+// gdbr-check:$16 = "Hello, World!"
 
 // === LLDB TESTS ==================================================================================
 
@@ -122,6 +124,8 @@
 // cdb-check:u32              : 0x20 [Type: unsigned int]
 // cdb-command:dx u64
 // cdb-check:u64              : 0x40 [Type: unsigned __int64]
+// cdb-command:dx f16
+// cdb-check:f16              : 1.500000 [Type: f16]
 // cdb-command:dx f32
 // cdb-check:f32              : 2.500000 [Type: float]
 // cdb-command:dx f64
@@ -134,6 +138,7 @@
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
+#![feature(f16)]
 
 fn main() {
     let b: bool = false;
@@ -148,6 +153,7 @@ fn main() {
     let u16: u16 = 16;
     let u32: u32 = 32;
     let u64: u64 = 64;
+    let f16: f16 = 1.5;
     let f32: f32 = 2.5;
     let f64: f64 = 3.5;
     let s: &str = "Hello, World!";
diff --git a/tests/debuginfo/borrowed-basic.rs b/tests/debuginfo/borrowed-basic.rs
index e48e3dd055e..e3cf74dab1e 100644
--- a/tests/debuginfo/borrowed-basic.rs
+++ b/tests/debuginfo/borrowed-basic.rs
@@ -42,11 +42,14 @@
 // gdb-command:print *u64_ref
 // gdb-check:$12 = 64
 
+// gdb-command:print *f16_ref
+// gdb-check:$13 = 1.5
+
 // gdb-command:print *f32_ref
-// gdb-check:$13 = 2.5
+// gdb-check:$14 = 2.5
 
 // gdb-command:print *f64_ref
-// gdb-check:$14 = 3.5
+// gdb-check:$15 = 3.5
 
 
 // === LLDB TESTS ==================================================================================
@@ -100,6 +103,10 @@
 // lldbg-check:[...] 64
 // lldbr-check:(u64) *u64_ref = 64
 
+// lldb-command:v *f16_ref
+// lldbg-check:[...] 1.5
+// lldbr-check:(f16) *f16_ref = 1.5
+
 // lldb-command:v *f32_ref
 // lldbg-check:[...] 2.5
 // lldbr-check:(f32) *f32_ref = 2.5
@@ -111,6 +118,7 @@
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
+#![feature(f16)]
 
 fn main() {
     let bool_val: bool = true;
@@ -149,6 +157,9 @@ fn main() {
     let u64_val: u64 = 64;
     let u64_ref: &u64 = &u64_val;
 
+    let f16_val: f16 = 1.5;
+    let f16_ref: &f16 = &f16_val;
+
     let f32_val: f32 = 2.5;
     let f32_ref: &f32 = &f32_val;
 
diff --git a/tests/debuginfo/borrowed-unique-basic.rs b/tests/debuginfo/borrowed-unique-basic.rs
index d6948a12851..e952ec8cebb 100644
--- a/tests/debuginfo/borrowed-unique-basic.rs
+++ b/tests/debuginfo/borrowed-unique-basic.rs
@@ -42,11 +42,14 @@
 // gdb-command:print *u64_ref
 // gdb-check:$12 = 64
 
+// gdb-command:print *f16_ref
+// gdb-check:$13 = 1.5
+
 // gdb-command:print *f32_ref
-// gdb-check:$13 = 2.5
+// gdb-check:$14 = 2.5
 
 // gdb-command:print *f64_ref
-// gdb-check:$14 = 3.5
+// gdb-check:$15 = 3.5
 
 
 // === LLDB TESTS ==================================================================================
@@ -103,6 +106,10 @@
 // lldbg-check:[...] 64
 // lldbr-check:(u64) *u64_ref = 64
 
+// lldb-command:v *f16_ref
+// lldbg-check:[...] 1.5
+// lldbr-check:(f16) *f16_ref = 1.5
+
 // lldb-command:v *f32_ref
 // lldbg-check:[...] 2.5
 // lldbr-check:(f32) *f32_ref = 2.5
@@ -114,6 +121,7 @@
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
+#![feature(f16)]
 
 fn main() {
     let bool_box: Box<bool> = Box::new(true);
@@ -152,6 +160,9 @@ fn main() {
     let u64_box: Box<u64> = Box::new(64);
     let u64_ref: &u64 = &*u64_box;
 
+    let f16_box: Box<f16> = Box::new(1.5);
+    let f16_ref: &f16 = &*f16_box;
+
     let f32_box: Box<f32> = Box::new(2.5);
     let f32_ref: &f32 = &*f32_box;
 
diff --git a/tests/debuginfo/f16-natvis.rs b/tests/debuginfo/f16-natvis.rs
new file mode 100644
index 00000000000..9b9749f2bad
--- /dev/null
+++ b/tests/debuginfo/f16-natvis.rs
@@ -0,0 +1,58 @@
+//@ compile-flags: -g
+//@ only-msvc
+
+// This tests the `f16` Natvis visualiser.
+// cdb-command:g
+// cdb-command:dx v0_0
+// cdb-check:v0_0             : 0.000000 [Type: f16]
+// cdb-command:dx neg_0_0
+// cdb-check:neg_0_0          : -0.000000 [Type: f16]
+// cdb-command:dx v1_0
+// cdb-check:v1_0             : 1.000000 [Type: f16]
+// cdb-command:dx v1_5
+// cdb-check:v1_5             : 1.500000 [Type: f16]
+// cdb-command:dx v72_3
+// cdb-check:v72_3            : 72.312500 [Type: f16]
+// cdb-command:dx neg_0_126
+// cdb-check:neg_0_126        : -0.125977 [Type: f16]
+// cdb-command:dx v0_00003
+// cdb-check:v0_00003         : 0.000030 [Type: f16]
+// cdb-command:dx neg_0_00004
+// cdb-check:neg_0_00004      : -0.000040 [Type: f16]
+// cdb-command:dx max
+// cdb-check:max              : 65504.000000 [Type: f16]
+// cdb-command:dx min
+// cdb-check:min              : -65504.000000 [Type: f16]
+// cdb-command:dx inf
+// cdb-check:inf              : inf [Type: f16]
+// cdb-command:dx neg_inf
+// cdb-check:neg_inf          : -inf [Type: f16]
+// cdb-command:dx nan
+// cdb-check:nan              : NaN [Type: f16]
+// cdb-command:dx other_nan
+// cdb-check:other_nan        : NaN [Type: f16]
+
+#![feature(f16)]
+
+fn main() {
+    let v0_0 = 0.0_f16;
+    let neg_0_0 = -0.0_f16;
+    let v1_0 = 1.0_f16;
+    let v1_5 = 1.5_f16;
+    let v72_3 = 72.3_f16;
+    let neg_0_126 = -0.126_f16;
+    let v0_00003 = 0.00003_f16;
+    let neg_0_00004 = -0.00004_f16;
+    let max = f16::MAX;
+    let min = f16::MIN;
+    let inf = f16::INFINITY;
+    let neg_inf = f16::NEG_INFINITY;
+    let nan = f16::NAN;
+    let other_nan = f16::from_bits(0xfc02);
+
+    _zzz(); // #break
+}
+
+fn _zzz() {
+    ()
+}
diff --git a/tests/debuginfo/reference-debuginfo.rs b/tests/debuginfo/reference-debuginfo.rs
index 339839f07cc..e2fb964ace5 100644
--- a/tests/debuginfo/reference-debuginfo.rs
+++ b/tests/debuginfo/reference-debuginfo.rs
@@ -46,14 +46,17 @@
 // gdb-command:print *u64_ref
 // gdb-check:$12 = 64
 
+// gdb-command:print *f16_ref
+// gdb-check:$13 = 1.5
+
 // gdb-command:print *f32_ref
-// gdb-check:$13 = 2.5
+// gdb-check:$14 = 2.5
 
 // gdb-command:print *f64_ref
-// gdb-check:$14 = 3.5
+// gdb-check:$15 = 3.5
 
 // gdb-command:print *f64_double_ref
-// gdb-check:$15 = 3.5
+// gdb-check:$16 = 3.5
 
 
 // === LLDB TESTS ==================================================================================
@@ -107,6 +110,10 @@
 // lldbg-check:[...] 64
 // lldbr-check:(u64) *u64_ref = 64
 
+// lldb-command:v *f16_ref
+// lldbg-check:[...] 1.5
+// lldbr-check:(f16) *f16_ref = 1.5
+
 // lldb-command:v *f32_ref
 // lldbg-check:[...] 2.5
 // lldbr-check:(f32) *f32_ref = 2.5
@@ -122,6 +129,7 @@
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
+#![feature(f16)]
 
 fn main() {
     let bool_val: bool = true;
@@ -160,6 +168,9 @@ fn main() {
     let u64_val: u64 = 64;
     let u64_ref: &u64 = &u64_val;
 
+    let f16_val: f16 = 1.5;
+    let f16_ref: &f16 = &f16_val;
+
     let f32_val: f32 = 2.5;
     let f32_ref: &f32 = &f32_val;
 
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir
index 06028487d01..1c34955a8d9 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir
@@ -1,6 +1,6 @@
 // MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move
 
-fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10}, _2: ResumeTy) -> ()
+fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> ()
 yields ()
  {
     debug _task_context => _2;
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
index 06028487d01..1c34955a8d9 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
@@ -1,6 +1,6 @@
 // MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move
 
-fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10}, _2: ResumeTy) -> ()
+fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> ()
 yields ()
  {
     debug _task_context => _2;
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir
index 93447b1388d..a984845fd2c 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir
@@ -1,10 +1,10 @@
 // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move
 
-fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:42:33: 42:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10} {
-    let mut _0: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10};
+fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:53:33: 53:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10} {
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10};
 
     bb0: {
-        _0 = {coroutine@$DIR/async_closure_shims.rs:42:53: 45:10 (#0)} { a: move _2, b: move (_1.0: i32) };
+        _0 = {coroutine@$DIR/async_closure_shims.rs:53:53: 56:10 (#0)} { a: move _2, b: move (_1.0: i32) };
         return;
     }
 }
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
index 93447b1388d..a984845fd2c 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
@@ -1,10 +1,10 @@
 // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move
 
-fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:42:33: 42:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10} {
-    let mut _0: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10};
+fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:53:33: 53:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10} {
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10};
 
     bb0: {
-        _0 = {coroutine@$DIR/async_closure_shims.rs:42:53: 45:10 (#0)} { a: move _2, b: move (_1.0: i32) };
+        _0 = {coroutine@$DIR/async_closure_shims.rs:53:53: 56:10 (#0)} { a: move _2, b: move (_1.0: i32) };
         return;
     }
 }
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir
new file mode 100644
index 00000000000..516908144a6
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-abort.mir
@@ -0,0 +1,47 @@
+// MIR for `main::{closure#0}::{closure#1}::{closure#0}` 0 coroutine_by_move
+
+fn main::{closure#0}::{closure#1}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> ()
+yields ()
+ {
+    debug _task_context => _2;
+    debug a => (_1.0: i32);
+    debug b => (*(_1.1: &i32));
+    let mut _0: ();
+    let _3: i32;
+    scope 1 {
+        debug a => _3;
+        let _4: &i32;
+        scope 2 {
+            debug a => _4;
+            let _5: &i32;
+            scope 3 {
+                debug b => _5;
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_3);
+        _3 = (_1.0: i32);
+        FakeRead(ForLet(None), _3);
+        StorageLive(_4);
+        _4 = &_3;
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = &(*(_1.1: &i32));
+        FakeRead(ForLet(None), _5);
+        _0 = const ();
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_1) -> [return: bb1, unwind: bb2];
+    }
+
+    bb1: {
+        return;
+    }
+
+    bb2 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
new file mode 100644
index 00000000000..516908144a6
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.panic-unwind.mir
@@ -0,0 +1,47 @@
+// MIR for `main::{closure#0}::{closure#1}::{closure#0}` 0 coroutine_by_move
+
+fn main::{closure#0}::{closure#1}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> ()
+yields ()
+ {
+    debug _task_context => _2;
+    debug a => (_1.0: i32);
+    debug b => (*(_1.1: &i32));
+    let mut _0: ();
+    let _3: i32;
+    scope 1 {
+        debug a => _3;
+        let _4: &i32;
+        scope 2 {
+            debug a => _4;
+            let _5: &i32;
+            scope 3 {
+                debug b => _5;
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_3);
+        _3 = (_1.0: i32);
+        FakeRead(ForLet(None), _3);
+        StorageLive(_4);
+        _4 = &_3;
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = &(*(_1.1: &i32));
+        FakeRead(ForLet(None), _5);
+        _0 = const ();
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_1) -> [return: bb1, unwind: bb2];
+    }
+
+    bb1: {
+        return;
+    }
+
+    bb2 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-abort.mir
new file mode 100644
index 00000000000..aab9f7b03b9
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-abort.mir
@@ -0,0 +1,10 @@
+// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_move
+
+fn main::{closure#0}::{closure#1}(_1: {async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} {
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10};
+
+    bb0: {
+        _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: move (_1.0: &i32) };
+        return;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir
new file mode 100644
index 00000000000..aab9f7b03b9
--- /dev/null
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.panic-unwind.mir
@@ -0,0 +1,10 @@
+// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_move
+
+fn main::{closure#0}::{closure#1}(_1: {async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} {
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10};
+
+    bb0: {
+        _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: move (_1.0: &i32) };
+        return;
+    }
+}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir
index cab7bdb7e3c..ba20c28cd01 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir
@@ -1,10 +1,10 @@
 // MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref
 
-fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
-    let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10};
+fn main::{closure#0}::{closure#1}(_1: &{async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} {
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10};
 
     bb0: {
-        _0 = {coroutine@$DIR/async_closure_shims.rs:49:49: 51:10 (#0)} { a: move _2 };
+        _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: ((*_1).0: &i32) };
         return;
     }
 }
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir
index cab7bdb7e3c..ba20c28cd01 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir
@@ -1,10 +1,10 @@
 // MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref
 
-fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
-    let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10};
+fn main::{closure#0}::{closure#1}(_1: &{async closure@$DIR/async_closure_shims.rs:62:33: 62:47}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10} {
+    let mut _0: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10};
 
     bb0: {
-        _0 = {coroutine@$DIR/async_closure_shims.rs:49:49: 51:10 (#0)} { a: move _2 };
+        _0 = {coroutine@$DIR/async_closure_shims.rs:62:48: 65:10 (#0)} { a: move _2, b: ((*_1).0: &i32) };
         return;
     }
 }
diff --git a/tests/mir-opt/async_closure_shims.rs b/tests/mir-opt/async_closure_shims.rs
index 7d226df6866..57c55ef055c 100644
--- a/tests/mir-opt/async_closure_shims.rs
+++ b/tests/mir-opt/async_closure_shims.rs
@@ -3,9 +3,10 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 #![feature(async_closure, noop_waker, async_fn_traits)]
+#![allow(unused)]
 
 use std::future::Future;
-use std::ops::{AsyncFnMut, AsyncFnOnce};
+use std::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
 use std::pin::pin;
 use std::task::*;
 
@@ -21,6 +22,10 @@ pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
     }
 }
 
+async fn call(f: &mut impl AsyncFn(i32)) {
+    f(0).await;
+}
+
 async fn call_mut(f: &mut impl AsyncFnMut(i32)) {
     f(0).await;
 }
@@ -33,9 +38,15 @@ async fn call_normal<F: Future<Output = ()>>(f: &impl Fn(i32) -> F) {
     f(1).await;
 }
 
+async fn call_normal_mut<F: Future<Output = ()>>(f: &mut impl FnMut(i32) -> F) {
+    f(1).await;
+}
+
 // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir
 // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.mir
 // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.mir
+// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.mir
+// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.coroutine_by_move.0.mir
 pub fn main() {
     block_on(async {
         let b = 2i32;
@@ -43,12 +54,17 @@ pub fn main() {
             let a = &a;
             let b = &b;
         };
+        call(&mut async_closure).await;
         call_mut(&mut async_closure).await;
         call_once(async_closure).await;
 
-        let async_closure = async move |a: i32| {
+        let b = 2i32;
+        let mut async_closure = async |a: i32| {
             let a = &a;
+            let b = &b;
         };
         call_normal(&async_closure).await;
+        call_normal_mut(&mut async_closure).await;
+        call_once(async_closure).await;
     });
 }
diff --git a/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir
new file mode 100644
index 00000000000..905aa19da70
--- /dev/null
+++ b/tests/mir-opt/building/match/simple_match.match_enum.built.after.mir
@@ -0,0 +1,60 @@
+// MIR for `match_enum` after built
+
+fn match_enum(_1: E1) -> bool {
+    debug x => _1;
+    let mut _0: bool;
+    let mut _2: isize;
+
+    bb0: {
+        PlaceMention(_1);
+        _2 = discriminant(_1);
+        switchInt(move _2) -> [0: bb3, 1: bb5, 2: bb7, otherwise: bb2];
+    }
+
+    bb1: {
+        FakeRead(ForMatchedPlace(None), _1);
+        unreachable;
+    }
+
+    bb2: {
+        goto -> bb1;
+    }
+
+    bb3: {
+        goto -> bb9;
+    }
+
+    bb4: {
+        goto -> bb2;
+    }
+
+    bb5: {
+        goto -> bb9;
+    }
+
+    bb6: {
+        goto -> bb2;
+    }
+
+    bb7: {
+        _0 = const false;
+        goto -> bb11;
+    }
+
+    bb8: {
+        goto -> bb2;
+    }
+
+    bb9: {
+        falseEdge -> [real: bb10, imaginary: bb7];
+    }
+
+    bb10: {
+        _0 = const true;
+        goto -> bb11;
+    }
+
+    bb11: {
+        return;
+    }
+}
diff --git a/tests/mir-opt/building/match/simple_match.rs b/tests/mir-opt/building/match/simple_match.rs
index 61c337822c8..c8b3d90748a 100644
--- a/tests/mir-opt/building/match/simple_match.rs
+++ b/tests/mir-opt/building/match/simple_match.rs
@@ -9,4 +9,18 @@ fn match_bool(x: bool) -> usize {
     }
 }
 
+pub enum E1 {
+    V1,
+    V2,
+    V3,
+}
+
+// EMIT_MIR simple_match.match_enum.built.after.mir
+pub fn match_enum(x: E1) -> bool {
+    match x {
+        E1::V1 | E1::V2 => true,
+        E1::V3 => false,
+    }
+}
+
 fn main() {}
diff --git a/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_direct.Inline.after.panic-abort.mir b/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_direct.Inline.after.panic-abort.mir
new file mode 100644
index 00000000000..522f772c6f4
--- /dev/null
+++ b/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_direct.Inline.after.panic-abort.mir
@@ -0,0 +1,22 @@
+// MIR for `marked_inline_direct` after Inline
+
+fn marked_inline_direct(_1: i32) -> () {
+    debug x => _1;
+    let mut _0: ();
+    let _2: ();
+    let mut _3: i32;
+
+    bb0: {
+        StorageLive(_2);
+        StorageLive(_3);
+        _3 = _1;
+        _2 = call_twice(move _3) -> [return: bb1, unwind unreachable];
+    }
+
+    bb1: {
+        StorageDead(_3);
+        StorageDead(_2);
+        _0 = const ();
+        return;
+    }
+}
diff --git a/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_direct.Inline.after.panic-unwind.mir b/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_direct.Inline.after.panic-unwind.mir
new file mode 100644
index 00000000000..722b02eeba8
--- /dev/null
+++ b/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_direct.Inline.after.panic-unwind.mir
@@ -0,0 +1,22 @@
+// MIR for `marked_inline_direct` after Inline
+
+fn marked_inline_direct(_1: i32) -> () {
+    debug x => _1;
+    let mut _0: ();
+    let _2: ();
+    let mut _3: i32;
+
+    bb0: {
+        StorageLive(_2);
+        StorageLive(_3);
+        _3 = _1;
+        _2 = call_twice(move _3) -> [return: bb1, unwind continue];
+    }
+
+    bb1: {
+        StorageDead(_3);
+        StorageDead(_2);
+        _0 = const ();
+        return;
+    }
+}
diff --git a/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_indirect.Inline.after.panic-abort.mir b/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_indirect.Inline.after.panic-abort.mir
new file mode 100644
index 00000000000..63b91cbce2d
--- /dev/null
+++ b/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_indirect.Inline.after.panic-abort.mir
@@ -0,0 +1,27 @@
+// MIR for `marked_inline_indirect` after Inline
+
+fn marked_inline_indirect(_1: i32) -> () {
+    debug x => _1;
+    let mut _0: ();
+    let _2: ();
+    let mut _3: i32;
+    scope 1 (inlined marked_inline_direct) {
+        let _4: ();
+    }
+
+    bb0: {
+        StorageLive(_2);
+        StorageLive(_3);
+        _3 = _1;
+        StorageLive(_4);
+        _4 = call_twice(move _3) -> [return: bb1, unwind unreachable];
+    }
+
+    bb1: {
+        StorageDead(_4);
+        StorageDead(_3);
+        StorageDead(_2);
+        _0 = const ();
+        return;
+    }
+}
diff --git a/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_indirect.Inline.after.panic-unwind.mir b/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_indirect.Inline.after.panic-unwind.mir
new file mode 100644
index 00000000000..7c84e98dd51
--- /dev/null
+++ b/tests/mir-opt/inline/inline_more_in_non_inline.marked_inline_indirect.Inline.after.panic-unwind.mir
@@ -0,0 +1,27 @@
+// MIR for `marked_inline_indirect` after Inline
+
+fn marked_inline_indirect(_1: i32) -> () {
+    debug x => _1;
+    let mut _0: ();
+    let _2: ();
+    let mut _3: i32;
+    scope 1 (inlined marked_inline_direct) {
+        let _4: ();
+    }
+
+    bb0: {
+        StorageLive(_2);
+        StorageLive(_3);
+        _3 = _1;
+        StorageLive(_4);
+        _4 = call_twice(move _3) -> [return: bb1, unwind continue];
+    }
+
+    bb1: {
+        StorageDead(_4);
+        StorageDead(_3);
+        StorageDead(_2);
+        _0 = const ();
+        return;
+    }
+}
diff --git a/tests/mir-opt/inline/inline_more_in_non_inline.monomorphic_not_inline.Inline.after.panic-abort.mir b/tests/mir-opt/inline/inline_more_in_non_inline.monomorphic_not_inline.Inline.after.panic-abort.mir
new file mode 100644
index 00000000000..989014b8b47
--- /dev/null
+++ b/tests/mir-opt/inline/inline_more_in_non_inline.monomorphic_not_inline.Inline.after.panic-abort.mir
@@ -0,0 +1,34 @@
+// MIR for `monomorphic_not_inline` after Inline
+
+fn monomorphic_not_inline(_1: i32) -> () {
+    debug x => _1;
+    let mut _0: ();
+    let _2: ();
+    let mut _3: i32;
+    scope 1 (inlined call_twice) {
+        let _4: ();
+        let _5: ();
+    }
+
+    bb0: {
+        StorageLive(_2);
+        StorageLive(_3);
+        _3 = _1;
+        StorageLive(_4);
+        StorageLive(_5);
+        _4 = other_thing(_3) -> [return: bb2, unwind unreachable];
+    }
+
+    bb1: {
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageDead(_3);
+        StorageDead(_2);
+        _0 = const ();
+        return;
+    }
+
+    bb2: {
+        _5 = other_thing(move _3) -> [return: bb1, unwind unreachable];
+    }
+}
diff --git a/tests/mir-opt/inline/inline_more_in_non_inline.monomorphic_not_inline.Inline.after.panic-unwind.mir b/tests/mir-opt/inline/inline_more_in_non_inline.monomorphic_not_inline.Inline.after.panic-unwind.mir
new file mode 100644
index 00000000000..bd200719bbb
--- /dev/null
+++ b/tests/mir-opt/inline/inline_more_in_non_inline.monomorphic_not_inline.Inline.after.panic-unwind.mir
@@ -0,0 +1,34 @@
+// MIR for `monomorphic_not_inline` after Inline
+
+fn monomorphic_not_inline(_1: i32) -> () {
+    debug x => _1;
+    let mut _0: ();
+    let _2: ();
+    let mut _3: i32;
+    scope 1 (inlined call_twice) {
+        let _4: ();
+        let _5: ();
+    }
+
+    bb0: {
+        StorageLive(_2);
+        StorageLive(_3);
+        _3 = _1;
+        StorageLive(_4);
+        StorageLive(_5);
+        _4 = other_thing(_3) -> [return: bb2, unwind continue];
+    }
+
+    bb1: {
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageDead(_3);
+        StorageDead(_2);
+        _0 = const ();
+        return;
+    }
+
+    bb2: {
+        _5 = other_thing(move _3) -> [return: bb1, unwind continue];
+    }
+}
diff --git a/tests/mir-opt/inline/inline_more_in_non_inline.rs b/tests/mir-opt/inline/inline_more_in_non_inline.rs
new file mode 100644
index 00000000000..5968b970470
--- /dev/null
+++ b/tests/mir-opt/inline/inline_more_in_non_inline.rs
@@ -0,0 +1,46 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -O --crate-type lib
+
+// To avoid MIR blow-up, don't inline large callees into simple shim callers,
+// but *do* inline other trivial things.
+
+extern "Rust" {
+    fn other_thing(x: i32);
+}
+
+#[inline]
+unsafe fn call_twice(x: i32) {
+    unsafe {
+        other_thing(x);
+        other_thing(x);
+    }
+}
+
+// EMIT_MIR inline_more_in_non_inline.monomorphic_not_inline.Inline.after.mir
+#[no_mangle]
+pub unsafe fn monomorphic_not_inline(x: i32) {
+    // CHECK-LABEL: monomorphic_not_inline
+    // CHECK: other_thing
+    // CHECK: other_thing
+    unsafe { call_twice(x) };
+}
+
+// EMIT_MIR inline_more_in_non_inline.marked_inline_direct.Inline.after.mir
+#[inline]
+pub unsafe fn marked_inline_direct(x: i32) {
+    // CHECK-LABEL: marked_inline_direct
+    // CHECK-NOT: other_thing
+    // CHECK: call_twice
+    // CHECK-NOT: other_thing
+    unsafe { call_twice(x) };
+}
+
+// EMIT_MIR inline_more_in_non_inline.marked_inline_indirect.Inline.after.mir
+#[inline]
+pub unsafe fn marked_inline_indirect(x: i32) {
+    // CHECK-LABEL: marked_inline_indirect
+    // CHECK-NOT: other_thing
+    // CHECK: call_twice
+    // CHECK-NOT: other_thing
+    unsafe { marked_inline_direct(x) };
+}
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
index 45ce933a55a..2a36ccaab11 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
@@ -11,30 +11,10 @@
 +     scope 1 (inlined std::ptr::drop_in_place::<Vec<A>> - shim(Some(Vec<A>))) {
 +         let mut _6: &mut std::vec::Vec<A>;
 +         let mut _7: ();
-+         scope 2 (inlined <Vec<A> as Drop>::drop) {
-+             let mut _8: *mut [A];
-+             let mut _9: *mut A;
-+             let mut _10: usize;
-+             scope 3 (inlined Vec::<A>::as_mut_ptr) {
-+                 let mut _11: &alloc::raw_vec::RawVec<A>;
-+                 scope 4 (inlined alloc::raw_vec::RawVec::<A>::ptr) {
-+                     let mut _13: std::ptr::NonNull<A>;
-+                     scope 5 (inlined Unique::<A>::as_ptr) {
-+                         scope 6 (inlined NonNull::<A>::as_ptr) {
-+                             let mut _12: *const A;
-+                         }
-+                     }
-+                 }
-+             }
-+             scope 7 (inlined slice_from_raw_parts_mut::<A>) {
-+                 scope 8 (inlined std::ptr::from_raw_parts_mut::<[A], A>) {
-+                 }
-+             }
-+         }
 +     }
-+     scope 9 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
-+         let mut _14: isize;
-+         let mut _15: isize;
++     scope 2 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
++         let mut _8: isize;
++         let mut _9: isize;
 +     }
   
       bb0: {
@@ -45,24 +25,7 @@
 +         StorageLive(_6);
 +         StorageLive(_7);
 +         _6 = &mut (*_4);
-+         StorageLive(_8);
-+         StorageLive(_9);
-+         StorageLive(_11);
-+         _11 = &((*_6).0: alloc::raw_vec::RawVec<A>);
-+         StorageLive(_13);
-+         _13 = ((((*_6).0: alloc::raw_vec::RawVec<A>).0: std::ptr::Unique<A>).0: std::ptr::NonNull<A>);
-+         StorageLive(_12);
-+         _12 = (_13.0: *const A);
-+         _9 = move _12 as *mut A (PtrToPtr);
-+         StorageDead(_12);
-+         StorageDead(_13);
-+         StorageDead(_11);
-+         StorageLive(_10);
-+         _10 = ((*_6).1: usize);
-+         _8 = *mut [A] from (_9, _10);
-+         StorageDead(_10);
-+         StorageDead(_9);
-+         _7 = std::ptr::drop_in_place::<[A]>(move _8) -> [return: bb2, unwind unreachable];
++         _7 = <Vec<A> as Drop>::drop(move _6) -> [return: bb2, unwind unreachable];
       }
   
       bb1: {
@@ -73,20 +36,19 @@
           StorageLive(_5);
           _5 = _2;
 -         _0 = std::ptr::drop_in_place::<Option<B>>(move _5) -> [return: bb2, unwind unreachable];
-+         StorageLive(_14);
-+         StorageLive(_15);
-+         _14 = discriminant((*_5));
-+         switchInt(move _14) -> [0: bb3, otherwise: bb4];
++         StorageLive(_8);
++         StorageLive(_9);
++         _8 = discriminant((*_5));
++         switchInt(move _8) -> [0: bb3, otherwise: bb4];
       }
   
       bb2: {
-+         StorageDead(_8);
 +         drop(((*_4).0: alloc::raw_vec::RawVec<A>)) -> [return: bb1, unwind unreachable];
 +     }
 + 
 +     bb3: {
-+         StorageDead(_15);
-+         StorageDead(_14);
++         StorageDead(_9);
++         StorageDead(_8);
           StorageDead(_5);
           return;
 +     }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
index 79c5bcfe9cd..fbb887fe76a 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
@@ -7,90 +7,19 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     let mut _11: std::slice::Iter<'_, T>;
     let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>;
     let mut _13: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _37: std::option::Option<&T>;
-    let mut _39: &impl Fn(&T);
-    let mut _40: (&T,);
-    let _41: ();
+    let mut _15: std::option::Option<&T>;
+    let mut _16: isize;
+    let mut _18: &impl Fn(&T);
+    let mut _19: (&T,);
+    let _20: ();
     scope 1 {
         debug iter => _13;
-        let _38: &T;
+        let _17: &T;
         scope 2 {
-            debug x => _38;
+            debug x => _17;
         }
         scope 17 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
-            scope 18 (inlined <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back) {
-                let mut _14: *const *const T;
-                let mut _15: *const std::ptr::NonNull<T>;
-                let mut _20: bool;
-                let mut _21: *const T;
-                let _36: &T;
-                scope 19 {
-                    let _16: std::ptr::NonNull<T>;
-                    let _22: usize;
-                    scope 20 {
-                    }
-                    scope 21 {
-                        scope 25 (inlined <NonNull<T> as PartialEq>::eq) {
-                            let mut _17: std::ptr::NonNull<T>;
-                            scope 26 (inlined NonNull::<T>::as_ptr) {
-                                let mut _18: *const T;
-                            }
-                            scope 27 (inlined NonNull::<T>::as_ptr) {
-                                let mut _19: *const T;
-                            }
-                        }
-                    }
-                    scope 22 (inlined std::ptr::const_ptr::<impl *const T>::addr) {
-                        scope 23 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) {
-                        }
-                    }
-                    scope 24 (inlined std::ptr::const_ptr::<impl *const *const T>::cast::<NonNull<T>>) {
-                    }
-                }
-                scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) {
-                    let _29: std::ptr::NonNull<T>;
-                    scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) {
-                        let mut _23: *mut *const T;
-                        let mut _24: *mut std::ptr::NonNull<T>;
-                        let mut _25: std::ptr::NonNull<T>;
-                        let mut _28: std::ptr::NonNull<T>;
-                        let mut _30: *mut *const T;
-                        let mut _31: *mut usize;
-                        let mut _32: usize;
-                        let mut _33: usize;
-                        scope 30 {
-                            scope 31 {
-                            }
-                            scope 32 {
-                                scope 35 (inlined NonNull::<T>::sub) {
-                                    scope 36 (inlined core::num::<impl isize>::unchecked_neg) {
-                                        scope 37 (inlined core::ub_checks::check_language_ub) {
-                                            scope 38 (inlined core::ub_checks::check_language_ub::runtime) {
-                                            }
-                                        }
-                                    }
-                                    scope 39 (inlined NonNull::<T>::offset) {
-                                        let mut _26: *const T;
-                                        let mut _27: *const T;
-                                    }
-                                }
-                            }
-                            scope 33 (inlined std::ptr::mut_ptr::<impl *mut *const T>::cast::<usize>) {
-                            }
-                            scope 34 (inlined std::ptr::mut_ptr::<impl *mut *const T>::cast::<NonNull<T>>) {
-                            }
-                        }
-                    }
-                    scope 40 (inlined NonNull::<T>::as_ref::<'_>) {
-                        let mut _34: std::ptr::NonNull<T>;
-                        scope 41 (inlined NonNull::<T>::as_ptr) {
-                            let mut _35: *const T;
-                        }
-                        scope 42 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) {
-                        }
-                    }
-                }
-            }
+            let mut _14: &mut std::slice::Iter<'_, T>;
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -178,147 +107,45 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb4: {
-        StorageLive(_37);
-        StorageLive(_22);
-        StorageLive(_21);
-        StorageLive(_16);
-        StorageLive(_36);
-        StorageLive(_20);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb6];
+        StorageLive(_15);
+        StorageLive(_14);
+        _14 = &mut (_13.0: std::slice::Iter<'_, T>);
+        _15 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind unreachable];
     }
 
     bb5: {
-        StorageLive(_15);
-        StorageLive(_14);
-        _14 = &raw const ((_13.0: std::slice::Iter<'_, T>).1: *const T);
-        _15 = _14 as *const std::ptr::NonNull<T> (PtrToPtr);
         StorageDead(_14);
-        _16 = (*_15);
-        StorageDead(_15);
-        StorageLive(_18);
-        StorageLive(_19);
-        StorageLive(_17);
-        _17 = ((_13.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>);
-        _18 = (_17.0: *const T);
-        StorageDead(_17);
-        _19 = (_16.0: *const T);
-        _20 = Eq(_18, _19);
-        StorageDead(_19);
-        StorageDead(_18);
-        goto -> bb7;
+        _16 = discriminant(_15);
+        switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10];
     }
 
     bb6: {
-        _21 = ((_13.0: std::slice::Iter<'_, T>).1: *const T);
-        _22 = _21 as usize (Transmute);
-        _20 = Eq(_22, const 0_usize);
-        goto -> bb7;
+        StorageDead(_15);
+        StorageDead(_13);
+        drop(_2) -> [return: bb7, unwind unreachable];
     }
 
     bb7: {
-        switchInt(move _20) -> [0: bb8, otherwise: bb16];
+        return;
     }
 
     bb8: {
-        StorageLive(_35);
-        StorageLive(_29);
-        StorageLive(_31);
-        StorageLive(_24);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb9, otherwise: bb13];
+        _17 = ((_15 as Some).0: &T);
+        StorageLive(_18);
+        _18 = &_2;
+        StorageLive(_19);
+        _19 = (_17,);
+        _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind unreachable];
     }
 
     bb9: {
-        StorageLive(_23);
-        _23 = &raw mut ((_13.0: std::slice::Iter<'_, T>).1: *const T);
-        _24 = _23 as *mut std::ptr::NonNull<T> (PtrToPtr);
-        StorageDead(_23);
-        StorageLive(_28);
-        _25 = (*_24);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb10, otherwise: bb11];
-    }
-
-    bb10: {
-        StorageLive(_27);
-        StorageLive(_26);
-        _26 = (_25.0: *const T);
-        _27 = Offset(move _26, const -1_isize);
-        StorageDead(_26);
-        _28 = NonNull::<T> { pointer: move _27 };
-        StorageDead(_27);
-        goto -> bb12;
-    }
-
-    bb11: {
-        _28 = _25;
-        goto -> bb12;
-    }
-
-    bb12: {
-        (*_24) = move _28;
-        StorageDead(_28);
-        _29 = (*_24);
-        goto -> bb14;
-    }
-
-    bb13: {
-        StorageLive(_30);
-        _30 = &raw mut ((_13.0: std::slice::Iter<'_, T>).1: *const T);
-        _31 = _30 as *mut usize (PtrToPtr);
-        StorageDead(_30);
-        StorageLive(_33);
-        StorageLive(_32);
-        _32 = (*_31);
-        _33 = SubUnchecked(move _32, const 1_usize);
-        StorageDead(_32);
-        (*_31) = move _33;
-        StorageDead(_33);
-        _29 = ((_13.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>);
-        goto -> bb14;
-    }
-
-    bb14: {
-        StorageDead(_24);
-        StorageDead(_31);
-        StorageLive(_34);
-        _34 = _29;
-        _35 = (_34.0: *const T);
-        StorageDead(_34);
-        _36 = &(*_35);
-        StorageDead(_29);
-        StorageDead(_35);
-        _37 = Option::<&T>::Some(_36);
-        StorageDead(_20);
-        StorageDead(_36);
-        StorageDead(_16);
-        StorageDead(_21);
-        StorageDead(_22);
-        _38 = ((_37 as Some).0: &T);
-        StorageLive(_39);
-        _39 = &_2;
-        StorageLive(_40);
-        _40 = (_38,);
-        _41 = <impl Fn(&T) as Fn<(&T,)>>::call(move _39, move _40) -> [return: bb15, unwind unreachable];
-    }
-
-    bb15: {
-        StorageDead(_40);
-        StorageDead(_39);
-        StorageDead(_37);
+        StorageDead(_19);
+        StorageDead(_18);
+        StorageDead(_15);
         goto -> bb4;
     }
 
-    bb16: {
-        StorageDead(_20);
-        StorageDead(_36);
-        StorageDead(_16);
-        StorageDead(_21);
-        StorageDead(_22);
-        StorageDead(_37);
-        StorageDead(_13);
-        drop(_2) -> [return: bb17, unwind unreachable];
-    }
-
-    bb17: {
-        return;
+    bb10: {
+        unreachable;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
index 7c107a23f9e..db9409f72ab 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
@@ -7,90 +7,19 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     let mut _11: std::slice::Iter<'_, T>;
     let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>;
     let mut _13: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _37: std::option::Option<&T>;
-    let mut _39: &impl Fn(&T);
-    let mut _40: (&T,);
-    let _41: ();
+    let mut _15: std::option::Option<&T>;
+    let mut _16: isize;
+    let mut _18: &impl Fn(&T);
+    let mut _19: (&T,);
+    let _20: ();
     scope 1 {
         debug iter => _13;
-        let _38: &T;
+        let _17: &T;
         scope 2 {
-            debug x => _38;
+            debug x => _17;
         }
         scope 17 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
-            scope 18 (inlined <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back) {
-                let mut _14: *const *const T;
-                let mut _15: *const std::ptr::NonNull<T>;
-                let mut _20: bool;
-                let mut _21: *const T;
-                let _36: &T;
-                scope 19 {
-                    let _16: std::ptr::NonNull<T>;
-                    let _22: usize;
-                    scope 20 {
-                    }
-                    scope 21 {
-                        scope 25 (inlined <NonNull<T> as PartialEq>::eq) {
-                            let mut _17: std::ptr::NonNull<T>;
-                            scope 26 (inlined NonNull::<T>::as_ptr) {
-                                let mut _18: *const T;
-                            }
-                            scope 27 (inlined NonNull::<T>::as_ptr) {
-                                let mut _19: *const T;
-                            }
-                        }
-                    }
-                    scope 22 (inlined std::ptr::const_ptr::<impl *const T>::addr) {
-                        scope 23 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) {
-                        }
-                    }
-                    scope 24 (inlined std::ptr::const_ptr::<impl *const *const T>::cast::<NonNull<T>>) {
-                    }
-                }
-                scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) {
-                    let _29: std::ptr::NonNull<T>;
-                    scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) {
-                        let mut _23: *mut *const T;
-                        let mut _24: *mut std::ptr::NonNull<T>;
-                        let mut _25: std::ptr::NonNull<T>;
-                        let mut _28: std::ptr::NonNull<T>;
-                        let mut _30: *mut *const T;
-                        let mut _31: *mut usize;
-                        let mut _32: usize;
-                        let mut _33: usize;
-                        scope 30 {
-                            scope 31 {
-                            }
-                            scope 32 {
-                                scope 35 (inlined NonNull::<T>::sub) {
-                                    scope 36 (inlined core::num::<impl isize>::unchecked_neg) {
-                                        scope 37 (inlined core::ub_checks::check_language_ub) {
-                                            scope 38 (inlined core::ub_checks::check_language_ub::runtime) {
-                                            }
-                                        }
-                                    }
-                                    scope 39 (inlined NonNull::<T>::offset) {
-                                        let mut _26: *const T;
-                                        let mut _27: *const T;
-                                    }
-                                }
-                            }
-                            scope 33 (inlined std::ptr::mut_ptr::<impl *mut *const T>::cast::<usize>) {
-                            }
-                            scope 34 (inlined std::ptr::mut_ptr::<impl *mut *const T>::cast::<NonNull<T>>) {
-                            }
-                        }
-                    }
-                    scope 40 (inlined NonNull::<T>::as_ref::<'_>) {
-                        let mut _34: std::ptr::NonNull<T>;
-                        scope 41 (inlined NonNull::<T>::as_ptr) {
-                            let mut _35: *const T;
-                        }
-                        scope 42 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) {
-                        }
-                    }
-                }
-            }
+            let mut _14: &mut std::slice::Iter<'_, T>;
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -178,155 +107,53 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb4: {
-        StorageLive(_37);
-        StorageLive(_22);
-        StorageLive(_21);
-        StorageLive(_16);
-        StorageLive(_36);
-        StorageLive(_20);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb6];
+        StorageLive(_15);
+        StorageLive(_14);
+        _14 = &mut (_13.0: std::slice::Iter<'_, T>);
+        _15 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind: bb11];
     }
 
     bb5: {
-        StorageLive(_15);
-        StorageLive(_14);
-        _14 = &raw const ((_13.0: std::slice::Iter<'_, T>).1: *const T);
-        _15 = _14 as *const std::ptr::NonNull<T> (PtrToPtr);
         StorageDead(_14);
-        _16 = (*_15);
-        StorageDead(_15);
-        StorageLive(_18);
-        StorageLive(_19);
-        StorageLive(_17);
-        _17 = ((_13.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>);
-        _18 = (_17.0: *const T);
-        StorageDead(_17);
-        _19 = (_16.0: *const T);
-        _20 = Eq(_18, _19);
-        StorageDead(_19);
-        StorageDead(_18);
-        goto -> bb7;
+        _16 = discriminant(_15);
+        switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10];
     }
 
     bb6: {
-        _21 = ((_13.0: std::slice::Iter<'_, T>).1: *const T);
-        _22 = _21 as usize (Transmute);
-        _20 = Eq(_22, const 0_usize);
-        goto -> bb7;
+        StorageDead(_15);
+        StorageDead(_13);
+        drop(_2) -> [return: bb7, unwind continue];
     }
 
     bb7: {
-        switchInt(move _20) -> [0: bb8, otherwise: bb18];
+        return;
     }
 
     bb8: {
-        StorageLive(_35);
-        StorageLive(_29);
-        StorageLive(_31);
-        StorageLive(_24);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb9, otherwise: bb13];
+        _17 = ((_15 as Some).0: &T);
+        StorageLive(_18);
+        _18 = &_2;
+        StorageLive(_19);
+        _19 = (_17,);
+        _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind: bb11];
     }
 
     bb9: {
-        StorageLive(_23);
-        _23 = &raw mut ((_13.0: std::slice::Iter<'_, T>).1: *const T);
-        _24 = _23 as *mut std::ptr::NonNull<T> (PtrToPtr);
-        StorageDead(_23);
-        StorageLive(_28);
-        _25 = (*_24);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb10, otherwise: bb11];
+        StorageDead(_19);
+        StorageDead(_18);
+        StorageDead(_15);
+        goto -> bb4;
     }
 
     bb10: {
-        StorageLive(_27);
-        StorageLive(_26);
-        _26 = (_25.0: *const T);
-        _27 = Offset(move _26, const -1_isize);
-        StorageDead(_26);
-        _28 = NonNull::<T> { pointer: move _27 };
-        StorageDead(_27);
-        goto -> bb12;
-    }
-
-    bb11: {
-        _28 = _25;
-        goto -> bb12;
-    }
-
-    bb12: {
-        (*_24) = move _28;
-        StorageDead(_28);
-        _29 = (*_24);
-        goto -> bb14;
-    }
-
-    bb13: {
-        StorageLive(_30);
-        _30 = &raw mut ((_13.0: std::slice::Iter<'_, T>).1: *const T);
-        _31 = _30 as *mut usize (PtrToPtr);
-        StorageDead(_30);
-        StorageLive(_33);
-        StorageLive(_32);
-        _32 = (*_31);
-        _33 = SubUnchecked(move _32, const 1_usize);
-        StorageDead(_32);
-        (*_31) = move _33;
-        StorageDead(_33);
-        _29 = ((_13.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>);
-        goto -> bb14;
+        unreachable;
     }
 
-    bb14: {
-        StorageDead(_24);
-        StorageDead(_31);
-        StorageLive(_34);
-        _34 = _29;
-        _35 = (_34.0: *const T);
-        StorageDead(_34);
-        _36 = &(*_35);
-        StorageDead(_29);
-        StorageDead(_35);
-        _37 = Option::<&T>::Some(_36);
-        StorageDead(_20);
-        StorageDead(_36);
-        StorageDead(_16);
-        StorageDead(_21);
-        StorageDead(_22);
-        _38 = ((_37 as Some).0: &T);
-        StorageLive(_39);
-        _39 = &_2;
-        StorageLive(_40);
-        _40 = (_38,);
-        _41 = <impl Fn(&T) as Fn<(&T,)>>::call(move _39, move _40) -> [return: bb15, unwind: bb16];
+    bb11 (cleanup): {
+        drop(_2) -> [return: bb12, unwind terminate(cleanup)];
     }
 
-    bb15: {
-        StorageDead(_40);
-        StorageDead(_39);
-        StorageDead(_37);
-        goto -> bb4;
-    }
-
-    bb16 (cleanup): {
-        drop(_2) -> [return: bb17, unwind terminate(cleanup)];
-    }
-
-    bb17 (cleanup): {
+    bb12 (cleanup): {
         resume;
     }
-
-    bb18: {
-        StorageDead(_20);
-        StorageDead(_36);
-        StorageDead(_16);
-        StorageDead(_21);
-        StorageDead(_22);
-        StorageDead(_37);
-        StorageDead(_13);
-        drop(_2) -> [return: bb19, unwind continue];
-    }
-
-    bb19: {
-        return;
-    }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir
index 2df346c081c..78f96bf4195 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir
@@ -3,205 +3,12 @@
 fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut T> {
     debug it => _1;
     let mut _0: std::option::Option<&mut T>;
-    scope 1 (inlined <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back) {
-        let mut _2: *const *mut T;
-        let mut _3: *const std::ptr::NonNull<T>;
-        let mut _8: bool;
-        let mut _9: *mut T;
-        let mut _25: &mut T;
-        scope 2 {
-            let _4: std::ptr::NonNull<T>;
-            let _10: usize;
-            scope 3 {
-            }
-            scope 4 {
-                scope 8 (inlined <NonNull<T> as PartialEq>::eq) {
-                    let mut _5: std::ptr::NonNull<T>;
-                    scope 9 (inlined NonNull::<T>::as_ptr) {
-                        let mut _6: *const T;
-                    }
-                    scope 10 (inlined NonNull::<T>::as_ptr) {
-                        let mut _7: *const T;
-                    }
-                }
-            }
-            scope 5 (inlined std::ptr::mut_ptr::<impl *mut T>::addr) {
-                scope 6 (inlined std::ptr::mut_ptr::<impl *mut T>::cast::<()>) {
-                }
-            }
-            scope 7 (inlined std::ptr::const_ptr::<impl *const *mut T>::cast::<NonNull<T>>) {
-            }
-        }
-        scope 11 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) {
-            let mut _17: std::ptr::NonNull<T>;
-            scope 12 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) {
-                let mut _11: *mut *mut T;
-                let mut _12: *mut std::ptr::NonNull<T>;
-                let mut _13: std::ptr::NonNull<T>;
-                let mut _16: std::ptr::NonNull<T>;
-                let mut _18: *mut *mut T;
-                let mut _19: *mut usize;
-                let mut _20: usize;
-                let mut _21: usize;
-                scope 13 {
-                    scope 14 {
-                    }
-                    scope 15 {
-                        scope 18 (inlined NonNull::<T>::sub) {
-                            scope 19 (inlined core::num::<impl isize>::unchecked_neg) {
-                                scope 20 (inlined core::ub_checks::check_language_ub) {
-                                    scope 21 (inlined core::ub_checks::check_language_ub::runtime) {
-                                    }
-                                }
-                            }
-                            scope 22 (inlined NonNull::<T>::offset) {
-                                let mut _14: *const T;
-                                let mut _15: *const T;
-                            }
-                        }
-                    }
-                    scope 16 (inlined std::ptr::mut_ptr::<impl *mut *mut T>::cast::<usize>) {
-                    }
-                    scope 17 (inlined std::ptr::mut_ptr::<impl *mut *mut T>::cast::<NonNull<T>>) {
-                    }
-                }
-            }
-            scope 23 (inlined NonNull::<T>::as_mut::<'_>) {
-                let mut _22: std::ptr::NonNull<T>;
-                let mut _24: *mut T;
-                scope 24 (inlined NonNull::<T>::as_ptr) {
-                    let mut _23: *const T;
-                }
-            }
-        }
-    }
 
     bb0: {
-        StorageLive(_10);
-        StorageLive(_9);
-        StorageLive(_4);
-        StorageLive(_25);
-        StorageLive(_8);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
+        _0 = <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back(move _1) -> [return: bb1, unwind unreachable];
     }
 
     bb1: {
-        StorageLive(_3);
-        StorageLive(_2);
-        _2 = &raw const ((*_1).1: *mut T);
-        _3 = _2 as *const std::ptr::NonNull<T> (PtrToPtr);
-        StorageDead(_2);
-        _4 = (*_3);
-        StorageDead(_3);
-        StorageLive(_6);
-        StorageLive(_7);
-        StorageLive(_5);
-        _5 = ((*_1).0: std::ptr::NonNull<T>);
-        _6 = (_5.0: *const T);
-        StorageDead(_5);
-        _7 = (_4.0: *const T);
-        _8 = Eq(_6, _7);
-        StorageDead(_7);
-        StorageDead(_6);
-        goto -> bb3;
-    }
-
-    bb2: {
-        _9 = ((*_1).1: *mut T);
-        _10 = _9 as usize (Transmute);
-        _8 = Eq(_10, const 0_usize);
-        goto -> bb3;
-    }
-
-    bb3: {
-        switchInt(move _8) -> [0: bb4, otherwise: bb11];
-    }
-
-    bb4: {
-        StorageLive(_24);
-        StorageLive(_17);
-        StorageLive(_19);
-        StorageLive(_12);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb9];
-    }
-
-    bb5: {
-        StorageLive(_11);
-        _11 = &raw mut ((*_1).1: *mut T);
-        _12 = _11 as *mut std::ptr::NonNull<T> (PtrToPtr);
-        StorageDead(_11);
-        StorageLive(_16);
-        _13 = (*_12);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb6, otherwise: bb7];
-    }
-
-    bb6: {
-        StorageLive(_15);
-        StorageLive(_14);
-        _14 = (_13.0: *const T);
-        _15 = Offset(move _14, const -1_isize);
-        StorageDead(_14);
-        _16 = NonNull::<T> { pointer: move _15 };
-        StorageDead(_15);
-        goto -> bb8;
-    }
-
-    bb7: {
-        _16 = _13;
-        goto -> bb8;
-    }
-
-    bb8: {
-        (*_12) = move _16;
-        StorageDead(_16);
-        _17 = (*_12);
-        goto -> bb10;
-    }
-
-    bb9: {
-        StorageLive(_18);
-        _18 = &raw mut ((*_1).1: *mut T);
-        _19 = _18 as *mut usize (PtrToPtr);
-        StorageDead(_18);
-        StorageLive(_21);
-        StorageLive(_20);
-        _20 = (*_19);
-        _21 = SubUnchecked(move _20, const 1_usize);
-        StorageDead(_20);
-        (*_19) = move _21;
-        StorageDead(_21);
-        _17 = ((*_1).0: std::ptr::NonNull<T>);
-        goto -> bb10;
-    }
-
-    bb10: {
-        StorageDead(_12);
-        StorageDead(_19);
-        StorageLive(_22);
-        _22 = _17;
-        StorageLive(_23);
-        _23 = (_22.0: *const T);
-        _24 = move _23 as *mut T (PtrToPtr);
-        StorageDead(_23);
-        StorageDead(_22);
-        _25 = &mut (*_24);
-        StorageDead(_17);
-        StorageDead(_24);
-        _0 = Option::<&mut T>::Some(_25);
-        goto -> bb12;
-    }
-
-    bb11: {
-        _0 = const {transmute(0x0000000000000000): Option<&mut T>};
-        goto -> bb12;
-    }
-
-    bb12: {
-        StorageDead(_8);
-        StorageDead(_25);
-        StorageDead(_4);
-        StorageDead(_9);
-        StorageDead(_10);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir
index 2df346c081c..dfe5e206fad 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir
@@ -3,205 +3,12 @@
 fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut T> {
     debug it => _1;
     let mut _0: std::option::Option<&mut T>;
-    scope 1 (inlined <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back) {
-        let mut _2: *const *mut T;
-        let mut _3: *const std::ptr::NonNull<T>;
-        let mut _8: bool;
-        let mut _9: *mut T;
-        let mut _25: &mut T;
-        scope 2 {
-            let _4: std::ptr::NonNull<T>;
-            let _10: usize;
-            scope 3 {
-            }
-            scope 4 {
-                scope 8 (inlined <NonNull<T> as PartialEq>::eq) {
-                    let mut _5: std::ptr::NonNull<T>;
-                    scope 9 (inlined NonNull::<T>::as_ptr) {
-                        let mut _6: *const T;
-                    }
-                    scope 10 (inlined NonNull::<T>::as_ptr) {
-                        let mut _7: *const T;
-                    }
-                }
-            }
-            scope 5 (inlined std::ptr::mut_ptr::<impl *mut T>::addr) {
-                scope 6 (inlined std::ptr::mut_ptr::<impl *mut T>::cast::<()>) {
-                }
-            }
-            scope 7 (inlined std::ptr::const_ptr::<impl *const *mut T>::cast::<NonNull<T>>) {
-            }
-        }
-        scope 11 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) {
-            let mut _17: std::ptr::NonNull<T>;
-            scope 12 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) {
-                let mut _11: *mut *mut T;
-                let mut _12: *mut std::ptr::NonNull<T>;
-                let mut _13: std::ptr::NonNull<T>;
-                let mut _16: std::ptr::NonNull<T>;
-                let mut _18: *mut *mut T;
-                let mut _19: *mut usize;
-                let mut _20: usize;
-                let mut _21: usize;
-                scope 13 {
-                    scope 14 {
-                    }
-                    scope 15 {
-                        scope 18 (inlined NonNull::<T>::sub) {
-                            scope 19 (inlined core::num::<impl isize>::unchecked_neg) {
-                                scope 20 (inlined core::ub_checks::check_language_ub) {
-                                    scope 21 (inlined core::ub_checks::check_language_ub::runtime) {
-                                    }
-                                }
-                            }
-                            scope 22 (inlined NonNull::<T>::offset) {
-                                let mut _14: *const T;
-                                let mut _15: *const T;
-                            }
-                        }
-                    }
-                    scope 16 (inlined std::ptr::mut_ptr::<impl *mut *mut T>::cast::<usize>) {
-                    }
-                    scope 17 (inlined std::ptr::mut_ptr::<impl *mut *mut T>::cast::<NonNull<T>>) {
-                    }
-                }
-            }
-            scope 23 (inlined NonNull::<T>::as_mut::<'_>) {
-                let mut _22: std::ptr::NonNull<T>;
-                let mut _24: *mut T;
-                scope 24 (inlined NonNull::<T>::as_ptr) {
-                    let mut _23: *const T;
-                }
-            }
-        }
-    }
 
     bb0: {
-        StorageLive(_10);
-        StorageLive(_9);
-        StorageLive(_4);
-        StorageLive(_25);
-        StorageLive(_8);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
+        _0 = <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back(move _1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
-        StorageLive(_3);
-        StorageLive(_2);
-        _2 = &raw const ((*_1).1: *mut T);
-        _3 = _2 as *const std::ptr::NonNull<T> (PtrToPtr);
-        StorageDead(_2);
-        _4 = (*_3);
-        StorageDead(_3);
-        StorageLive(_6);
-        StorageLive(_7);
-        StorageLive(_5);
-        _5 = ((*_1).0: std::ptr::NonNull<T>);
-        _6 = (_5.0: *const T);
-        StorageDead(_5);
-        _7 = (_4.0: *const T);
-        _8 = Eq(_6, _7);
-        StorageDead(_7);
-        StorageDead(_6);
-        goto -> bb3;
-    }
-
-    bb2: {
-        _9 = ((*_1).1: *mut T);
-        _10 = _9 as usize (Transmute);
-        _8 = Eq(_10, const 0_usize);
-        goto -> bb3;
-    }
-
-    bb3: {
-        switchInt(move _8) -> [0: bb4, otherwise: bb11];
-    }
-
-    bb4: {
-        StorageLive(_24);
-        StorageLive(_17);
-        StorageLive(_19);
-        StorageLive(_12);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb9];
-    }
-
-    bb5: {
-        StorageLive(_11);
-        _11 = &raw mut ((*_1).1: *mut T);
-        _12 = _11 as *mut std::ptr::NonNull<T> (PtrToPtr);
-        StorageDead(_11);
-        StorageLive(_16);
-        _13 = (*_12);
-        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb6, otherwise: bb7];
-    }
-
-    bb6: {
-        StorageLive(_15);
-        StorageLive(_14);
-        _14 = (_13.0: *const T);
-        _15 = Offset(move _14, const -1_isize);
-        StorageDead(_14);
-        _16 = NonNull::<T> { pointer: move _15 };
-        StorageDead(_15);
-        goto -> bb8;
-    }
-
-    bb7: {
-        _16 = _13;
-        goto -> bb8;
-    }
-
-    bb8: {
-        (*_12) = move _16;
-        StorageDead(_16);
-        _17 = (*_12);
-        goto -> bb10;
-    }
-
-    bb9: {
-        StorageLive(_18);
-        _18 = &raw mut ((*_1).1: *mut T);
-        _19 = _18 as *mut usize (PtrToPtr);
-        StorageDead(_18);
-        StorageLive(_21);
-        StorageLive(_20);
-        _20 = (*_19);
-        _21 = SubUnchecked(move _20, const 1_usize);
-        StorageDead(_20);
-        (*_19) = move _21;
-        StorageDead(_21);
-        _17 = ((*_1).0: std::ptr::NonNull<T>);
-        goto -> bb10;
-    }
-
-    bb10: {
-        StorageDead(_12);
-        StorageDead(_19);
-        StorageLive(_22);
-        _22 = _17;
-        StorageLive(_23);
-        _23 = (_22.0: *const T);
-        _24 = move _23 as *mut T (PtrToPtr);
-        StorageDead(_23);
-        StorageDead(_22);
-        _25 = &mut (*_24);
-        StorageDead(_17);
-        StorageDead(_24);
-        _0 = Option::<&mut T>::Some(_25);
-        goto -> bb12;
-    }
-
-    bb11: {
-        _0 = const {transmute(0x0000000000000000): Option<&mut T>};
-        goto -> bb12;
-    }
-
-    bb12: {
-        StorageDead(_8);
-        StorageDead(_25);
-        StorageDead(_4);
-        StorageDead(_9);
-        StorageDead(_10);
         return;
     }
 }
diff --git a/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-abort.diff b/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-abort.diff
new file mode 100644
index 00000000000..44673ea00a9
--- /dev/null
+++ b/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-abort.diff
@@ -0,0 +1,108 @@
+- // MIR for `f` before ElaborateDrops
++ // MIR for `f` after ElaborateDrops
+  
+  fn f() -> () {
+      let mut _0: ();
+      let mut _1: !;
+      let _2: std::string::String;
+      let _6: ();
+      let mut _7: std::string::String;
++     let mut _8: bool;
+      scope 1 {
+          debug _a => _2;
+          let _3: i32;
+          scope 2 {
+              debug _b => _3;
+              let _4: std::string::String;
+              scope 3 {
+                  debug _c => _4;
+                  let _5: std::string::String;
+                  scope 4 {
+                      debug _d => _5;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
++         _8 = const false;
+          StorageLive(_2);
+          _2 = String::new() -> [return: bb1, unwind: bb12];
+      }
+  
+      bb1: {
+          StorageLive(_3);
+          _3 = const 12_i32;
+          StorageLive(_4);
+          _4 = String::new() -> [return: bb2, unwind: bb11];
+      }
+  
+      bb2: {
++         _8 = const true;
+          StorageLive(_5);
+          _5 = String::new() -> [return: bb3, unwind: bb10];
+      }
+  
+      bb3: {
+          StorageLive(_6);
+          StorageLive(_7);
++         _8 = const false;
+          _7 = move _4;
+          _6 = std::mem::drop::<String>(move _7) -> [return: bb4, unwind: bb8];
+      }
+  
+      bb4: {
+          StorageDead(_7);
+          StorageDead(_6);
+          drop(_5) -> [return: bb5, unwind: bb10];
+      }
+  
+      bb5: {
+          StorageDead(_5);
+-         drop(_4) -> [return: bb6, unwind: bb11];
++         goto -> bb6;
+      }
+  
+      bb6: {
++         _8 = const false;
+          StorageDead(_4);
+          StorageDead(_3);
+          drop(_2) -> [return: bb7, unwind: bb12];
+      }
+  
+      bb7: {
+          StorageDead(_2);
+          tailcall g();
+      }
+  
+      bb8 (cleanup): {
+-         drop(_7) -> [return: bb9, unwind terminate(cleanup)];
++         goto -> bb9;
+      }
+  
+      bb9 (cleanup): {
+          drop(_5) -> [return: bb10, unwind terminate(cleanup)];
+      }
+  
+      bb10 (cleanup): {
+-         drop(_4) -> [return: bb11, unwind terminate(cleanup)];
++         goto -> bb14;
+      }
+  
+      bb11 (cleanup): {
+          drop(_2) -> [return: bb12, unwind terminate(cleanup)];
+      }
+  
+      bb12 (cleanup): {
+          resume;
++     }
++ 
++     bb13 (cleanup): {
++         drop(_4) -> [return: bb11, unwind terminate(cleanup)];
++     }
++ 
++     bb14 (cleanup): {
++         switchInt(_8) -> [0: bb11, otherwise: bb13];
+      }
+  }
+  
diff --git a/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-unwind.diff
new file mode 100644
index 00000000000..a6d33a24595
--- /dev/null
+++ b/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-unwind.diff
@@ -0,0 +1,109 @@
+- // MIR for `f` before ElaborateDrops
++ // MIR for `f` after ElaborateDrops
+  
+  fn f() -> () {
+      let mut _0: ();
+      let mut _1: !;
+      let _2: std::string::String;
+      let _6: ();
+      let mut _7: std::string::String;
++     let mut _8: bool;
+      scope 1 {
+          debug _a => _2;
+          let _3: i32;
+          scope 2 {
+              debug _b => _3;
+              let _4: std::string::String;
+              scope 3 {
+                  debug _c => _4;
+                  let _5: std::string::String;
+                  scope 4 {
+                      debug _d => _5;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
++         _8 = const false;
+          StorageLive(_2);
+          _2 = String::new() -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          StorageLive(_3);
+          _3 = const 12_i32;
+          StorageLive(_4);
+          _4 = String::new() -> [return: bb2, unwind: bb11];
+      }
+  
+      bb2: {
++         _8 = const true;
+          StorageLive(_5);
+          _5 = String::new() -> [return: bb3, unwind: bb10];
+      }
+  
+      bb3: {
+          StorageLive(_6);
+          StorageLive(_7);
++         _8 = const false;
+          _7 = move _4;
+          _6 = std::mem::drop::<String>(move _7) -> [return: bb4, unwind: bb8];
+      }
+  
+      bb4: {
+          StorageDead(_7);
+          StorageDead(_6);
+          drop(_5) -> [return: bb5, unwind: bb10];
+      }
+  
+      bb5: {
+          StorageDead(_5);
+-         drop(_4) -> [return: bb6, unwind: bb11];
++         goto -> bb6;
+      }
+  
+      bb6: {
++         _8 = const false;
+          StorageDead(_4);
+          StorageDead(_3);
+-         drop(_2) -> [return: bb7, unwind continue];
++         drop(_2) -> [return: bb7, unwind: bb12];
+      }
+  
+      bb7: {
+          StorageDead(_2);
+          tailcall g();
+      }
+  
+      bb8 (cleanup): {
+-         drop(_7) -> [return: bb9, unwind terminate(cleanup)];
++         goto -> bb9;
+      }
+  
+      bb9 (cleanup): {
+          drop(_5) -> [return: bb10, unwind terminate(cleanup)];
+      }
+  
+      bb10 (cleanup): {
+-         drop(_4) -> [return: bb11, unwind terminate(cleanup)];
++         goto -> bb14;
+      }
+  
+      bb11 (cleanup): {
+          drop(_2) -> [return: bb12, unwind terminate(cleanup)];
+      }
+  
+      bb12 (cleanup): {
+          resume;
++     }
++ 
++     bb13 (cleanup): {
++         drop(_4) -> [return: bb11, unwind terminate(cleanup)];
++     }
++ 
++     bb14 (cleanup): {
++         switchInt(_8) -> [0: bb11, otherwise: bb13];
+      }
+  }
+  
diff --git a/tests/mir-opt/tail_call_drops.f.built.after.panic-abort.mir b/tests/mir-opt/tail_call_drops.f.built.after.panic-abort.mir
new file mode 100644
index 00000000000..2c3d62491d7
--- /dev/null
+++ b/tests/mir-opt/tail_call_drops.f.built.after.panic-abort.mir
@@ -0,0 +1,118 @@
+// MIR for `f` after built
+
+fn f() -> () {
+    let mut _0: ();
+    let mut _1: !;
+    let _2: std::string::String;
+    let _6: ();
+    let mut _7: std::string::String;
+    scope 1 {
+        debug _a => _2;
+        let _3: i32;
+        scope 2 {
+            debug _b => _3;
+            let _4: std::string::String;
+            scope 3 {
+                debug _c => _4;
+                let _5: std::string::String;
+                scope 4 {
+                    debug _d => _5;
+                }
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_2);
+        _2 = String::new() -> [return: bb1, unwind: bb17];
+    }
+
+    bb1: {
+        FakeRead(ForLet(None), _2);
+        StorageLive(_3);
+        _3 = const 12_i32;
+        FakeRead(ForLet(None), _3);
+        StorageLive(_4);
+        _4 = String::new() -> [return: bb2, unwind: bb16];
+    }
+
+    bb2: {
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = String::new() -> [return: bb3, unwind: bb15];
+    }
+
+    bb3: {
+        FakeRead(ForLet(None), _5);
+        StorageLive(_6);
+        StorageLive(_7);
+        _7 = move _4;
+        _6 = std::mem::drop::<String>(move _7) -> [return: bb4, unwind: bb13];
+    }
+
+    bb4: {
+        StorageDead(_7);
+        StorageDead(_6);
+        drop(_5) -> [return: bb5, unwind: bb15];
+    }
+
+    bb5: {
+        StorageDead(_5);
+        drop(_4) -> [return: bb6, unwind: bb16];
+    }
+
+    bb6: {
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_2) -> [return: bb7, unwind: bb17];
+    }
+
+    bb7: {
+        StorageDead(_2);
+        tailcall g();
+    }
+
+    bb8: {
+        drop(_5) -> [return: bb9, unwind: bb15];
+    }
+
+    bb9: {
+        StorageDead(_5);
+        drop(_4) -> [return: bb10, unwind: bb16];
+    }
+
+    bb10: {
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_2) -> [return: bb11, unwind: bb17];
+    }
+
+    bb11: {
+        StorageDead(_2);
+        unreachable;
+    }
+
+    bb12: {
+        return;
+    }
+
+    bb13 (cleanup): {
+        drop(_7) -> [return: bb14, unwind terminate(cleanup)];
+    }
+
+    bb14 (cleanup): {
+        drop(_5) -> [return: bb15, unwind terminate(cleanup)];
+    }
+
+    bb15 (cleanup): {
+        drop(_4) -> [return: bb16, unwind terminate(cleanup)];
+    }
+
+    bb16 (cleanup): {
+        drop(_2) -> [return: bb17, unwind terminate(cleanup)];
+    }
+
+    bb17 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/tail_call_drops.f.built.after.panic-unwind.mir b/tests/mir-opt/tail_call_drops.f.built.after.panic-unwind.mir
new file mode 100644
index 00000000000..2c3d62491d7
--- /dev/null
+++ b/tests/mir-opt/tail_call_drops.f.built.after.panic-unwind.mir
@@ -0,0 +1,118 @@
+// MIR for `f` after built
+
+fn f() -> () {
+    let mut _0: ();
+    let mut _1: !;
+    let _2: std::string::String;
+    let _6: ();
+    let mut _7: std::string::String;
+    scope 1 {
+        debug _a => _2;
+        let _3: i32;
+        scope 2 {
+            debug _b => _3;
+            let _4: std::string::String;
+            scope 3 {
+                debug _c => _4;
+                let _5: std::string::String;
+                scope 4 {
+                    debug _d => _5;
+                }
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_2);
+        _2 = String::new() -> [return: bb1, unwind: bb17];
+    }
+
+    bb1: {
+        FakeRead(ForLet(None), _2);
+        StorageLive(_3);
+        _3 = const 12_i32;
+        FakeRead(ForLet(None), _3);
+        StorageLive(_4);
+        _4 = String::new() -> [return: bb2, unwind: bb16];
+    }
+
+    bb2: {
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = String::new() -> [return: bb3, unwind: bb15];
+    }
+
+    bb3: {
+        FakeRead(ForLet(None), _5);
+        StorageLive(_6);
+        StorageLive(_7);
+        _7 = move _4;
+        _6 = std::mem::drop::<String>(move _7) -> [return: bb4, unwind: bb13];
+    }
+
+    bb4: {
+        StorageDead(_7);
+        StorageDead(_6);
+        drop(_5) -> [return: bb5, unwind: bb15];
+    }
+
+    bb5: {
+        StorageDead(_5);
+        drop(_4) -> [return: bb6, unwind: bb16];
+    }
+
+    bb6: {
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_2) -> [return: bb7, unwind: bb17];
+    }
+
+    bb7: {
+        StorageDead(_2);
+        tailcall g();
+    }
+
+    bb8: {
+        drop(_5) -> [return: bb9, unwind: bb15];
+    }
+
+    bb9: {
+        StorageDead(_5);
+        drop(_4) -> [return: bb10, unwind: bb16];
+    }
+
+    bb10: {
+        StorageDead(_4);
+        StorageDead(_3);
+        drop(_2) -> [return: bb11, unwind: bb17];
+    }
+
+    bb11: {
+        StorageDead(_2);
+        unreachable;
+    }
+
+    bb12: {
+        return;
+    }
+
+    bb13 (cleanup): {
+        drop(_7) -> [return: bb14, unwind terminate(cleanup)];
+    }
+
+    bb14 (cleanup): {
+        drop(_5) -> [return: bb15, unwind terminate(cleanup)];
+    }
+
+    bb15 (cleanup): {
+        drop(_4) -> [return: bb16, unwind terminate(cleanup)];
+    }
+
+    bb16 (cleanup): {
+        drop(_2) -> [return: bb17, unwind terminate(cleanup)];
+    }
+
+    bb17 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-abort.diff b/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-abort.diff
new file mode 100644
index 00000000000..c7df2bb2207
--- /dev/null
+++ b/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-abort.diff
@@ -0,0 +1,184 @@
+- // MIR for `f_with_arg` before ElaborateDrops
++ // MIR for `f_with_arg` after ElaborateDrops
+  
+  fn f_with_arg(_1: String, _2: String) -> () {
+      debug _arg1 => _1;
+      debug _arg2 => _2;
+      let mut _0: ();
+      let mut _3: !;
+      let _4: std::string::String;
+      let _8: ();
+      let mut _9: std::string::String;
+      let mut _10: std::string::String;
+      let mut _11: std::string::String;
++     let mut _12: bool;
+      scope 1 {
+          debug _a => _4;
+          let _5: i32;
+          scope 2 {
+              debug _b => _5;
+              let _6: std::string::String;
+              scope 3 {
+                  debug _c => _6;
+                  let _7: std::string::String;
+                  scope 4 {
+                      debug _d => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
++         _12 = const false;
+          StorageLive(_4);
+          _4 = String::new() -> [return: bb1, unwind: bb27];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = const 12_i32;
+          StorageLive(_6);
+          _6 = String::new() -> [return: bb2, unwind: bb26];
+      }
+  
+      bb2: {
++         _12 = const true;
+          StorageLive(_7);
+          _7 = String::new() -> [return: bb3, unwind: bb25];
+      }
+  
+      bb3: {
+          StorageLive(_8);
+          StorageLive(_9);
++         _12 = const false;
+          _9 = move _6;
+          _8 = std::mem::drop::<String>(move _9) -> [return: bb4, unwind: bb23];
+      }
+  
+      bb4: {
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageLive(_10);
+          _10 = String::new() -> [return: bb5, unwind: bb24];
+      }
+  
+      bb5: {
+          StorageLive(_11);
+          _11 = String::new() -> [return: bb6, unwind: bb22];
+      }
+  
+      bb6: {
+          drop(_7) -> [return: bb7, unwind: bb20];
+      }
+  
+      bb7: {
+          StorageDead(_7);
+-         drop(_6) -> [return: bb8, unwind: bb18];
++         goto -> bb8;
+      }
+  
+      bb8: {
++         _12 = const false;
+          StorageDead(_6);
+          StorageDead(_5);
+          drop(_4) -> [return: bb9, unwind: bb16];
+      }
+  
+      bb9: {
+          StorageDead(_4);
+          drop(_2) -> [return: bb10, unwind: bb14];
+      }
+  
+      bb10: {
+          drop(_1) -> [return: bb11, unwind: bb12];
+      }
+  
+      bb11: {
+          tailcall g_with_arg(Spanned { node: move _10, span: $DIR/tail_call_drops.rs:36:23: 36:36 (#0) }, Spanned { node: move _11, span: $DIR/tail_call_drops.rs:36:38: 36:51 (#0) });
+      }
+  
+      bb12 (cleanup): {
+          drop(_10) -> [return: bb13, unwind terminate(cleanup)];
+      }
+  
+      bb13 (cleanup): {
+          drop(_11) -> [return: bb29, unwind terminate(cleanup)];
+      }
+  
+      bb14 (cleanup): {
+          drop(_10) -> [return: bb15, unwind terminate(cleanup)];
+      }
+  
+      bb15 (cleanup): {
+          drop(_11) -> [return: bb28, unwind terminate(cleanup)];
+      }
+  
+      bb16 (cleanup): {
+          drop(_10) -> [return: bb17, unwind terminate(cleanup)];
+      }
+  
+      bb17 (cleanup): {
+          drop(_11) -> [return: bb27, unwind terminate(cleanup)];
+      }
+  
+      bb18 (cleanup): {
+-         drop(_10) -> [return: bb19, unwind terminate(cleanup)];
++         goto -> bb19;
+      }
+  
+      bb19 (cleanup): {
+-         drop(_11) -> [return: bb26, unwind terminate(cleanup)];
++         goto -> bb26;
+      }
+  
+      bb20 (cleanup): {
+          drop(_10) -> [return: bb21, unwind terminate(cleanup)];
+      }
+  
+      bb21 (cleanup): {
+          drop(_11) -> [return: bb25, unwind terminate(cleanup)];
+      }
+  
+      bb22 (cleanup): {
+          drop(_10) -> [return: bb24, unwind terminate(cleanup)];
+      }
+  
+      bb23 (cleanup): {
+-         drop(_9) -> [return: bb24, unwind terminate(cleanup)];
++         goto -> bb24;
+      }
+  
+      bb24 (cleanup): {
+          drop(_7) -> [return: bb25, unwind terminate(cleanup)];
+      }
+  
+      bb25 (cleanup): {
+-         drop(_6) -> [return: bb26, unwind terminate(cleanup)];
++         goto -> bb31;
+      }
+  
+      bb26 (cleanup): {
+          drop(_4) -> [return: bb27, unwind terminate(cleanup)];
+      }
+  
+      bb27 (cleanup): {
+          drop(_2) -> [return: bb28, unwind terminate(cleanup)];
+      }
+  
+      bb28 (cleanup): {
+          drop(_1) -> [return: bb29, unwind terminate(cleanup)];
+      }
+  
+      bb29 (cleanup): {
+          resume;
++     }
++ 
++     bb30 (cleanup): {
++         drop(_6) -> [return: bb26, unwind terminate(cleanup)];
++     }
++ 
++     bb31 (cleanup): {
++         switchInt(_12) -> [0: bb26, otherwise: bb30];
+      }
+  }
+  
diff --git a/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-unwind.diff
new file mode 100644
index 00000000000..c7df2bb2207
--- /dev/null
+++ b/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-unwind.diff
@@ -0,0 +1,184 @@
+- // MIR for `f_with_arg` before ElaborateDrops
++ // MIR for `f_with_arg` after ElaborateDrops
+  
+  fn f_with_arg(_1: String, _2: String) -> () {
+      debug _arg1 => _1;
+      debug _arg2 => _2;
+      let mut _0: ();
+      let mut _3: !;
+      let _4: std::string::String;
+      let _8: ();
+      let mut _9: std::string::String;
+      let mut _10: std::string::String;
+      let mut _11: std::string::String;
++     let mut _12: bool;
+      scope 1 {
+          debug _a => _4;
+          let _5: i32;
+          scope 2 {
+              debug _b => _5;
+              let _6: std::string::String;
+              scope 3 {
+                  debug _c => _6;
+                  let _7: std::string::String;
+                  scope 4 {
+                      debug _d => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
++         _12 = const false;
+          StorageLive(_4);
+          _4 = String::new() -> [return: bb1, unwind: bb27];
+      }
+  
+      bb1: {
+          StorageLive(_5);
+          _5 = const 12_i32;
+          StorageLive(_6);
+          _6 = String::new() -> [return: bb2, unwind: bb26];
+      }
+  
+      bb2: {
++         _12 = const true;
+          StorageLive(_7);
+          _7 = String::new() -> [return: bb3, unwind: bb25];
+      }
+  
+      bb3: {
+          StorageLive(_8);
+          StorageLive(_9);
++         _12 = const false;
+          _9 = move _6;
+          _8 = std::mem::drop::<String>(move _9) -> [return: bb4, unwind: bb23];
+      }
+  
+      bb4: {
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageLive(_10);
+          _10 = String::new() -> [return: bb5, unwind: bb24];
+      }
+  
+      bb5: {
+          StorageLive(_11);
+          _11 = String::new() -> [return: bb6, unwind: bb22];
+      }
+  
+      bb6: {
+          drop(_7) -> [return: bb7, unwind: bb20];
+      }
+  
+      bb7: {
+          StorageDead(_7);
+-         drop(_6) -> [return: bb8, unwind: bb18];
++         goto -> bb8;
+      }
+  
+      bb8: {
++         _12 = const false;
+          StorageDead(_6);
+          StorageDead(_5);
+          drop(_4) -> [return: bb9, unwind: bb16];
+      }
+  
+      bb9: {
+          StorageDead(_4);
+          drop(_2) -> [return: bb10, unwind: bb14];
+      }
+  
+      bb10: {
+          drop(_1) -> [return: bb11, unwind: bb12];
+      }
+  
+      bb11: {
+          tailcall g_with_arg(Spanned { node: move _10, span: $DIR/tail_call_drops.rs:36:23: 36:36 (#0) }, Spanned { node: move _11, span: $DIR/tail_call_drops.rs:36:38: 36:51 (#0) });
+      }
+  
+      bb12 (cleanup): {
+          drop(_10) -> [return: bb13, unwind terminate(cleanup)];
+      }
+  
+      bb13 (cleanup): {
+          drop(_11) -> [return: bb29, unwind terminate(cleanup)];
+      }
+  
+      bb14 (cleanup): {
+          drop(_10) -> [return: bb15, unwind terminate(cleanup)];
+      }
+  
+      bb15 (cleanup): {
+          drop(_11) -> [return: bb28, unwind terminate(cleanup)];
+      }
+  
+      bb16 (cleanup): {
+          drop(_10) -> [return: bb17, unwind terminate(cleanup)];
+      }
+  
+      bb17 (cleanup): {
+          drop(_11) -> [return: bb27, unwind terminate(cleanup)];
+      }
+  
+      bb18 (cleanup): {
+-         drop(_10) -> [return: bb19, unwind terminate(cleanup)];
++         goto -> bb19;
+      }
+  
+      bb19 (cleanup): {
+-         drop(_11) -> [return: bb26, unwind terminate(cleanup)];
++         goto -> bb26;
+      }
+  
+      bb20 (cleanup): {
+          drop(_10) -> [return: bb21, unwind terminate(cleanup)];
+      }
+  
+      bb21 (cleanup): {
+          drop(_11) -> [return: bb25, unwind terminate(cleanup)];
+      }
+  
+      bb22 (cleanup): {
+          drop(_10) -> [return: bb24, unwind terminate(cleanup)];
+      }
+  
+      bb23 (cleanup): {
+-         drop(_9) -> [return: bb24, unwind terminate(cleanup)];
++         goto -> bb24;
+      }
+  
+      bb24 (cleanup): {
+          drop(_7) -> [return: bb25, unwind terminate(cleanup)];
+      }
+  
+      bb25 (cleanup): {
+-         drop(_6) -> [return: bb26, unwind terminate(cleanup)];
++         goto -> bb31;
+      }
+  
+      bb26 (cleanup): {
+          drop(_4) -> [return: bb27, unwind terminate(cleanup)];
+      }
+  
+      bb27 (cleanup): {
+          drop(_2) -> [return: bb28, unwind terminate(cleanup)];
+      }
+  
+      bb28 (cleanup): {
+          drop(_1) -> [return: bb29, unwind terminate(cleanup)];
+      }
+  
+      bb29 (cleanup): {
+          resume;
++     }
++ 
++     bb30 (cleanup): {
++         drop(_6) -> [return: bb26, unwind terminate(cleanup)];
++     }
++ 
++     bb31 (cleanup): {
++         switchInt(_12) -> [0: bb26, otherwise: bb30];
+      }
+  }
+  
diff --git a/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-abort.mir b/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-abort.mir
new file mode 100644
index 00000000000..744f1989acc
--- /dev/null
+++ b/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-abort.mir
@@ -0,0 +1,202 @@
+// MIR for `f_with_arg` after built
+
+fn f_with_arg(_1: String, _2: String) -> () {
+    debug _arg1 => _1;
+    debug _arg2 => _2;
+    let mut _0: ();
+    let mut _3: !;
+    let _4: std::string::String;
+    let _8: ();
+    let mut _9: std::string::String;
+    let mut _10: std::string::String;
+    let mut _11: std::string::String;
+    scope 1 {
+        debug _a => _4;
+        let _5: i32;
+        scope 2 {
+            debug _b => _5;
+            let _6: std::string::String;
+            scope 3 {
+                debug _c => _6;
+                let _7: std::string::String;
+                scope 4 {
+                    debug _d => _7;
+                }
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_4);
+        _4 = String::new() -> [return: bb1, unwind: bb34];
+    }
+
+    bb1: {
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = const 12_i32;
+        FakeRead(ForLet(None), _5);
+        StorageLive(_6);
+        _6 = String::new() -> [return: bb2, unwind: bb33];
+    }
+
+    bb2: {
+        FakeRead(ForLet(None), _6);
+        StorageLive(_7);
+        _7 = String::new() -> [return: bb3, unwind: bb32];
+    }
+
+    bb3: {
+        FakeRead(ForLet(None), _7);
+        StorageLive(_8);
+        StorageLive(_9);
+        _9 = move _6;
+        _8 = std::mem::drop::<String>(move _9) -> [return: bb4, unwind: bb30];
+    }
+
+    bb4: {
+        StorageDead(_9);
+        StorageDead(_8);
+        StorageLive(_10);
+        _10 = String::new() -> [return: bb5, unwind: bb31];
+    }
+
+    bb5: {
+        StorageLive(_11);
+        _11 = String::new() -> [return: bb6, unwind: bb29];
+    }
+
+    bb6: {
+        drop(_7) -> [return: bb7, unwind: bb27];
+    }
+
+    bb7: {
+        StorageDead(_7);
+        drop(_6) -> [return: bb8, unwind: bb25];
+    }
+
+    bb8: {
+        StorageDead(_6);
+        StorageDead(_5);
+        drop(_4) -> [return: bb9, unwind: bb23];
+    }
+
+    bb9: {
+        StorageDead(_4);
+        drop(_2) -> [return: bb10, unwind: bb21];
+    }
+
+    bb10: {
+        drop(_1) -> [return: bb11, unwind: bb19];
+    }
+
+    bb11: {
+        tailcall g_with_arg(Spanned { node: move _10, span: $DIR/tail_call_drops.rs:36:23: 36:36 (#0) }, Spanned { node: move _11, span: $DIR/tail_call_drops.rs:36:38: 36:51 (#0) });
+    }
+
+    bb12: {
+        StorageDead(_11);
+        StorageDead(_10);
+        drop(_7) -> [return: bb13, unwind: bb32];
+    }
+
+    bb13: {
+        StorageDead(_7);
+        drop(_6) -> [return: bb14, unwind: bb33];
+    }
+
+    bb14: {
+        StorageDead(_6);
+        StorageDead(_5);
+        drop(_4) -> [return: bb15, unwind: bb34];
+    }
+
+    bb15: {
+        StorageDead(_4);
+        unreachable;
+    }
+
+    bb16: {
+        drop(_2) -> [return: bb17, unwind: bb35];
+    }
+
+    bb17: {
+        drop(_1) -> [return: bb18, unwind: bb36];
+    }
+
+    bb18: {
+        return;
+    }
+
+    bb19 (cleanup): {
+        drop(_10) -> [return: bb20, unwind terminate(cleanup)];
+    }
+
+    bb20 (cleanup): {
+        drop(_11) -> [return: bb36, unwind terminate(cleanup)];
+    }
+
+    bb21 (cleanup): {
+        drop(_10) -> [return: bb22, unwind terminate(cleanup)];
+    }
+
+    bb22 (cleanup): {
+        drop(_11) -> [return: bb35, unwind terminate(cleanup)];
+    }
+
+    bb23 (cleanup): {
+        drop(_10) -> [return: bb24, unwind terminate(cleanup)];
+    }
+
+    bb24 (cleanup): {
+        drop(_11) -> [return: bb34, unwind terminate(cleanup)];
+    }
+
+    bb25 (cleanup): {
+        drop(_10) -> [return: bb26, unwind terminate(cleanup)];
+    }
+
+    bb26 (cleanup): {
+        drop(_11) -> [return: bb33, unwind terminate(cleanup)];
+    }
+
+    bb27 (cleanup): {
+        drop(_10) -> [return: bb28, unwind terminate(cleanup)];
+    }
+
+    bb28 (cleanup): {
+        drop(_11) -> [return: bb32, unwind terminate(cleanup)];
+    }
+
+    bb29 (cleanup): {
+        drop(_10) -> [return: bb31, unwind terminate(cleanup)];
+    }
+
+    bb30 (cleanup): {
+        drop(_9) -> [return: bb31, unwind terminate(cleanup)];
+    }
+
+    bb31 (cleanup): {
+        drop(_7) -> [return: bb32, unwind terminate(cleanup)];
+    }
+
+    bb32 (cleanup): {
+        drop(_6) -> [return: bb33, unwind terminate(cleanup)];
+    }
+
+    bb33 (cleanup): {
+        drop(_4) -> [return: bb34, unwind terminate(cleanup)];
+    }
+
+    bb34 (cleanup): {
+        drop(_2) -> [return: bb35, unwind terminate(cleanup)];
+    }
+
+    bb35 (cleanup): {
+        drop(_1) -> [return: bb36, unwind terminate(cleanup)];
+    }
+
+    bb36 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-unwind.mir b/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-unwind.mir
new file mode 100644
index 00000000000..744f1989acc
--- /dev/null
+++ b/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-unwind.mir
@@ -0,0 +1,202 @@
+// MIR for `f_with_arg` after built
+
+fn f_with_arg(_1: String, _2: String) -> () {
+    debug _arg1 => _1;
+    debug _arg2 => _2;
+    let mut _0: ();
+    let mut _3: !;
+    let _4: std::string::String;
+    let _8: ();
+    let mut _9: std::string::String;
+    let mut _10: std::string::String;
+    let mut _11: std::string::String;
+    scope 1 {
+        debug _a => _4;
+        let _5: i32;
+        scope 2 {
+            debug _b => _5;
+            let _6: std::string::String;
+            scope 3 {
+                debug _c => _6;
+                let _7: std::string::String;
+                scope 4 {
+                    debug _d => _7;
+                }
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_4);
+        _4 = String::new() -> [return: bb1, unwind: bb34];
+    }
+
+    bb1: {
+        FakeRead(ForLet(None), _4);
+        StorageLive(_5);
+        _5 = const 12_i32;
+        FakeRead(ForLet(None), _5);
+        StorageLive(_6);
+        _6 = String::new() -> [return: bb2, unwind: bb33];
+    }
+
+    bb2: {
+        FakeRead(ForLet(None), _6);
+        StorageLive(_7);
+        _7 = String::new() -> [return: bb3, unwind: bb32];
+    }
+
+    bb3: {
+        FakeRead(ForLet(None), _7);
+        StorageLive(_8);
+        StorageLive(_9);
+        _9 = move _6;
+        _8 = std::mem::drop::<String>(move _9) -> [return: bb4, unwind: bb30];
+    }
+
+    bb4: {
+        StorageDead(_9);
+        StorageDead(_8);
+        StorageLive(_10);
+        _10 = String::new() -> [return: bb5, unwind: bb31];
+    }
+
+    bb5: {
+        StorageLive(_11);
+        _11 = String::new() -> [return: bb6, unwind: bb29];
+    }
+
+    bb6: {
+        drop(_7) -> [return: bb7, unwind: bb27];
+    }
+
+    bb7: {
+        StorageDead(_7);
+        drop(_6) -> [return: bb8, unwind: bb25];
+    }
+
+    bb8: {
+        StorageDead(_6);
+        StorageDead(_5);
+        drop(_4) -> [return: bb9, unwind: bb23];
+    }
+
+    bb9: {
+        StorageDead(_4);
+        drop(_2) -> [return: bb10, unwind: bb21];
+    }
+
+    bb10: {
+        drop(_1) -> [return: bb11, unwind: bb19];
+    }
+
+    bb11: {
+        tailcall g_with_arg(Spanned { node: move _10, span: $DIR/tail_call_drops.rs:36:23: 36:36 (#0) }, Spanned { node: move _11, span: $DIR/tail_call_drops.rs:36:38: 36:51 (#0) });
+    }
+
+    bb12: {
+        StorageDead(_11);
+        StorageDead(_10);
+        drop(_7) -> [return: bb13, unwind: bb32];
+    }
+
+    bb13: {
+        StorageDead(_7);
+        drop(_6) -> [return: bb14, unwind: bb33];
+    }
+
+    bb14: {
+        StorageDead(_6);
+        StorageDead(_5);
+        drop(_4) -> [return: bb15, unwind: bb34];
+    }
+
+    bb15: {
+        StorageDead(_4);
+        unreachable;
+    }
+
+    bb16: {
+        drop(_2) -> [return: bb17, unwind: bb35];
+    }
+
+    bb17: {
+        drop(_1) -> [return: bb18, unwind: bb36];
+    }
+
+    bb18: {
+        return;
+    }
+
+    bb19 (cleanup): {
+        drop(_10) -> [return: bb20, unwind terminate(cleanup)];
+    }
+
+    bb20 (cleanup): {
+        drop(_11) -> [return: bb36, unwind terminate(cleanup)];
+    }
+
+    bb21 (cleanup): {
+        drop(_10) -> [return: bb22, unwind terminate(cleanup)];
+    }
+
+    bb22 (cleanup): {
+        drop(_11) -> [return: bb35, unwind terminate(cleanup)];
+    }
+
+    bb23 (cleanup): {
+        drop(_10) -> [return: bb24, unwind terminate(cleanup)];
+    }
+
+    bb24 (cleanup): {
+        drop(_11) -> [return: bb34, unwind terminate(cleanup)];
+    }
+
+    bb25 (cleanup): {
+        drop(_10) -> [return: bb26, unwind terminate(cleanup)];
+    }
+
+    bb26 (cleanup): {
+        drop(_11) -> [return: bb33, unwind terminate(cleanup)];
+    }
+
+    bb27 (cleanup): {
+        drop(_10) -> [return: bb28, unwind terminate(cleanup)];
+    }
+
+    bb28 (cleanup): {
+        drop(_11) -> [return: bb32, unwind terminate(cleanup)];
+    }
+
+    bb29 (cleanup): {
+        drop(_10) -> [return: bb31, unwind terminate(cleanup)];
+    }
+
+    bb30 (cleanup): {
+        drop(_9) -> [return: bb31, unwind terminate(cleanup)];
+    }
+
+    bb31 (cleanup): {
+        drop(_7) -> [return: bb32, unwind terminate(cleanup)];
+    }
+
+    bb32 (cleanup): {
+        drop(_6) -> [return: bb33, unwind terminate(cleanup)];
+    }
+
+    bb33 (cleanup): {
+        drop(_4) -> [return: bb34, unwind terminate(cleanup)];
+    }
+
+    bb34 (cleanup): {
+        drop(_2) -> [return: bb35, unwind terminate(cleanup)];
+    }
+
+    bb35 (cleanup): {
+        drop(_1) -> [return: bb36, unwind terminate(cleanup)];
+    }
+
+    bb36 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/tail_call_drops.rs b/tests/mir-opt/tail_call_drops.rs
new file mode 100644
index 00000000000..56f4852a95f
--- /dev/null
+++ b/tests/mir-opt/tail_call_drops.rs
@@ -0,0 +1,41 @@
+// skip-filecheck
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+// EMIT_MIR tail_call_drops.f.built.after.mir
+//   Expected result:
+//   drop(_d) -> drop(_c) -> drop(_a) -> tailcall g()
+//
+// EMIT_MIR tail_call_drops.f.ElaborateDrops.diff
+//   Expected result:
+//   drop(_d) ->             drop(_a) -> tailcall g()
+fn f() {
+    let _a = String::new();
+    let _b = 12;
+    let _c = String::new();
+    let _d = String::new();
+
+    drop(_c);
+
+    become g();
+}
+
+fn g() {}
+
+// EMIT_MIR tail_call_drops.f_with_arg.built.after.mir
+// EMIT_MIR tail_call_drops.f_with_arg.ElaborateDrops.diff
+fn f_with_arg(_arg1: String, _arg2: String) {
+    let _a = String::new();
+    let _b = 12;
+    let _c = String::new();
+    let _d = String::new();
+
+    drop(_c);
+
+    become g_with_arg(String::new(), String::new());
+}
+
+fn g_with_arg(_arg1: String, _arg2: String) {}
+
+fn main() {}
diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp
index 018ccf82dae..fa958d9f1e8 100644
--- a/tests/pretty/issue-4264.pp
+++ b/tests/pretty/issue-4264.pp
@@ -29,16 +29,17 @@ fn bar() ({
 
 
 
-    ({
-        let res =
-            ((::alloc::fmt::format as
-                    for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
-                        as
-                        fn(&[&'static str; 1]) -> Arguments<'_> {Arguments::<'_>::new_const::<1>})((&([("test"
-                                    as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
-                as String);
-        (res as String)
-    } as String);
+    ((::alloc::__export::must_use as
+            fn(String) -> String {must_use::<String>})(({
+            let res =
+                ((::alloc::fmt::format as
+                        for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
+                            as
+                            fn(&[&'static str; 1]) -> Arguments<'_> {Arguments::<'_>::new_const::<1>})((&([("test"
+                                        as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
+                    as String);
+            (res as String)
+        } as String)) as String);
 } as ())
 type Foo = [i32; (3 as usize)];
 struct Bar {
diff --git a/tests/run-make/comment-section/rmake.rs b/tests/run-make/comment-section/rmake.rs
index 41df04da7a5..188c6dcb25d 100644
--- a/tests/run-make/comment-section/rmake.rs
+++ b/tests/run-make/comment-section/rmake.rs
@@ -21,7 +21,7 @@ fn main() {
         .stdin("fn main() {}")
         .emit("link,obj")
         .arg("-Csave-temps")
-        .target(&target)
+        .target(target)
         .run();
 
     // Check linked output has a `.comment` section with the expected content.
diff --git a/tests/run-make/compressed-debuginfo/rmake.rs b/tests/run-make/compressed-debuginfo/rmake.rs
index 9c6d50ab243..3a656f28c22 100644
--- a/tests/run-make/compressed-debuginfo/rmake.rs
+++ b/tests/run-make/compressed-debuginfo/rmake.rs
@@ -5,7 +5,7 @@
 
 // FIXME: This test isn't comprehensive and isn't covering all possible combinations.
 
-use run_make_support::{assert_contains, cmd, run_in_tmpdir, rustc};
+use run_make_support::{assert_contains, cmd, llvm_readobj, run_in_tmpdir, rustc};
 
 fn check_compression(compression: &str, to_find: &str) {
     run_in_tmpdir(|| {
@@ -19,12 +19,11 @@ fn check_compression(compression: &str, to_find: &str) {
             .run();
         let stderr = out.stderr_utf8();
         if stderr.is_empty() {
-            // FIXME: `readelf` might need to be replaced with `llvm-readelf`.
-            cmd("readelf").arg("-t").arg("foo.o").run().assert_stdout_contains(to_find);
+            llvm_readobj().arg("-t").arg("foo.o").run().assert_stdout_contains(to_find);
         } else {
             assert_contains(
-                &stderr,
-                &format!("unknown debuginfo compression algorithm {compression}"),
+                stderr,
+                format!("unknown debuginfo compression algorithm {compression}"),
             );
         }
     });
diff --git a/tests/run-make/dylib-chain/Makefile b/tests/run-make/dylib-chain/Makefile
deleted file mode 100644
index f1fea99c5ee..00000000000
--- a/tests/run-make/dylib-chain/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) m1.rs -C prefer-dynamic
-	$(RUSTC) m2.rs -C prefer-dynamic
-	$(RUSTC) m3.rs -C prefer-dynamic
-	$(RUSTC) m4.rs
-	$(call RUN,m4)
-	$(call REMOVE_DYLIBS,m1)
-	$(call REMOVE_DYLIBS,m2)
-	$(call REMOVE_DYLIBS,m3)
-	$(call FAIL,m4)
diff --git a/tests/run-make/dylib-chain/rmake.rs b/tests/run-make/dylib-chain/rmake.rs
new file mode 100644
index 00000000000..a96cc350875
--- /dev/null
+++ b/tests/run-make/dylib-chain/rmake.rs
@@ -0,0 +1,23 @@
+// In this test, m4 depends on m3, which depends on m2, which depends on m1.
+// Even though dependencies are chained like this and there is no direct mention
+// of m1 or m2 in m4.rs, compilation and execution should still succeed. Unlike the
+// rlib-chain test, dynamic libraries contain upstream dependencies, and breaking
+// the chain by removing the dylibs causes execution to fail.
+// See https://github.com/rust-lang/rust/issues/10434
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{dynamic_lib_name, fs_wrapper, run, run_fail, rustc};
+
+fn main() {
+    rustc().input("m1.rs").arg("-Cprefer-dynamic").run();
+    rustc().input("m2.rs").arg("-Cprefer-dynamic").run();
+    rustc().input("m3.rs").arg("-Cprefer-dynamic").run();
+    rustc().input("m4.rs").run();
+    run("m4");
+    fs_wrapper::remove_file(dynamic_lib_name("m1"));
+    fs_wrapper::remove_file(dynamic_lib_name("m2"));
+    fs_wrapper::remove_file(dynamic_lib_name("m3"));
+    run_fail("m4");
+}
diff --git a/tests/run-make/dylib-soname/foo.rs b/tests/run-make/dylib-soname/foo.rs
new file mode 100644
index 00000000000..6833f391999
--- /dev/null
+++ b/tests/run-make/dylib-soname/foo.rs
@@ -0,0 +1 @@
+pub fn something() {}
diff --git a/tests/run-make/dylib-soname/rmake.rs b/tests/run-make/dylib-soname/rmake.rs
new file mode 100644
index 00000000000..a0215a6906e
--- /dev/null
+++ b/tests/run-make/dylib-soname/rmake.rs
@@ -0,0 +1,19 @@
+// Checks that produced dylibs have a relative SONAME set, so they don't put "unmovable" full paths
+// into DT_NEEDED when used by a full path.
+
+//@ only-linux
+//@ ignore-cross-compile
+
+use run_make_support::regex::Regex;
+use run_make_support::{cmd, run_in_tmpdir, rustc};
+
+fn main() {
+    run_in_tmpdir(|| {
+        rustc().crate_name("foo").crate_type("dylib").input("foo.rs").run();
+        cmd("readelf")
+            .arg("-d")
+            .arg("libfoo.so")
+            .run()
+            .assert_stdout_contains("Library soname: [libfoo.so]");
+    });
+}
diff --git a/tests/run-make/emit-named-files/rmake.rs b/tests/run-make/emit-named-files/rmake.rs
index 79c3ee90c98..a02c97fec4c 100644
--- a/tests/run-make/emit-named-files/rmake.rs
+++ b/tests/run-make/emit-named-files/rmake.rs
@@ -4,7 +4,7 @@ use run_make_support::{fs_wrapper, rustc};
 
 fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) {
     let out_file = out_dir.join(out_file);
-    rustc().input("foo.rs").emit(&format!("{format}={}", out_file.display())).run();
+    rustc().input("foo.rs").emit(format!("{format}={}", out_file.display())).run();
     assert!(out_file.is_file());
 }
 
diff --git a/tests/run-make/emit-path-unhashed/Makefile b/tests/run-make/emit-path-unhashed/Makefile
deleted file mode 100644
index 611f8578140..00000000000
--- a/tests/run-make/emit-path-unhashed/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-include ../tools.mk
-
-OUT=$(TMPDIR)/emit
-
-# --emit KIND=PATH should not affect crate hash vs --emit KIND
-all: $(OUT)/a/libfoo.rlib $(OUT)/b/libfoo.rlib $(OUT)/c/libfoo.rlib \
-		$(TMPDIR)/libfoo.rlib
-	$(RUSTC) -Zls=root $(TMPDIR)/libfoo.rlib > $(TMPDIR)/base.txt
-	$(RUSTC) -Zls=root $(OUT)/a/libfoo.rlib > $(TMPDIR)/a.txt
-	$(RUSTC) -Zls=root $(OUT)/b/libfoo.rlib > $(TMPDIR)/b.txt
-	$(RUSTC) -Zls=root $(OUT)/c/libfoo.rlib > $(TMPDIR)/c.txt
-
-	diff $(TMPDIR)/base.txt $(TMPDIR)/a.txt
-	diff $(TMPDIR)/base.txt $(TMPDIR)/b.txt
-
-	# Different KIND parameters do affect hash.
-	# diff exits 1 on difference, 2 on trouble
-	diff $(TMPDIR)/base.txt $(TMPDIR)/c.txt ; test "$$?" -eq 1
-
-# Default output name
-$(TMPDIR)/libfoo.rlib: foo.rs
-	$(RUSTC) --emit link foo.rs
-
-# Output named with -o
-$(OUT)/a/libfoo.rlib: foo.rs
-	mkdir -p $(OUT)/a
-	$(RUSTC) --emit link -o $@ foo.rs
-
-# Output named with KIND=PATH
-$(OUT)/b/libfoo.rlib: foo.rs
-	mkdir -p $(OUT)/b
-	$(RUSTC) --emit link=$@ foo.rs
-
-# Output multiple kinds
-$(OUT)/c/libfoo.rlib: foo.rs
-	mkdir -p $(OUT)/c
-	$(RUSTC) --emit link=$@,metadata foo.rs
diff --git a/tests/run-make/emit-path-unhashed/rmake.rs b/tests/run-make/emit-path-unhashed/rmake.rs
new file mode 100644
index 00000000000..ce56c197588
--- /dev/null
+++ b/tests/run-make/emit-path-unhashed/rmake.rs
@@ -0,0 +1,34 @@
+// Specifying how rustc outputs a file can be done in different ways, such as
+// the output flag or the KIND=NAME syntax. However, some of these methods used
+// to result in different hashes on output files even though they yielded the
+// exact same result otherwise. This was fixed in #86045, and this test checks
+// that the hash is only modified when the output is made different, such as by
+// adding a new output type (in this test, metadata).
+// See https://github.com/rust-lang/rust/issues/86044
+
+use run_make_support::{diff, fs_wrapper, rustc};
+
+fn main() {
+    fs_wrapper::create_dir("emit");
+    fs_wrapper::create_dir("emit/a");
+    fs_wrapper::create_dir("emit/b");
+    fs_wrapper::create_dir("emit/c");
+    // The default output name.
+    rustc().emit("link").input("foo.rs").run();
+    // The output is named with the output flag.
+    rustc().emit("link").output("emit/a/libfoo.rlib").input("foo.rs").run();
+    // The output is named with link=NAME.
+    rustc().emit("link=emit/b/libfoo.rlib").input("foo.rs").run();
+    // The output is named with link=NAME, with an additional kind tacked on.
+    rustc().emit("link=emit/c/libfoo.rlib,metadata").input("foo.rs").run();
+
+    let base = rustc().arg("-Zls=root").input("libfoo.rlib").run().stdout_utf8();
+    let a = rustc().arg("-Zls=root").input("emit/a/libfoo.rlib").run().stdout_utf8();
+    let b = rustc().arg("-Zls=root").input("emit/b/libfoo.rlib").run().stdout_utf8();
+    let c = rustc().arg("-Zls=root").input("emit/c/libfoo.rlib").run().stdout_utf8();
+    // Both the output flag and link=NAME methods do not modify the hash of the output file.
+    diff().expected_text("base", &base).actual_text("a", a).run();
+    diff().expected_text("base", &base).actual_text("b", b).run();
+    // However, having multiple types of outputs does modify the hash.
+    diff().expected_text("base", &base).actual_text("c", c).run_fail();
+}
diff --git a/tests/run-make/emit-shared-files/Makefile b/tests/run-make/emit-shared-files/Makefile
deleted file mode 100644
index 27c72b00368..00000000000
--- a/tests/run-make/emit-shared-files/Makefile
+++ /dev/null
@@ -1,46 +0,0 @@
-include ../tools.mk
-
-INVOCATION_ONLY = $(TMPDIR)/invocation-only
-TOOLCHAIN_ONLY = $(TMPDIR)/toolchain-only
-ALL_SHARED = $(TMPDIR)/all-shared
-
-all: invocation-only toolchain-only all-shared
-
-invocation-only:
-	$(RUSTDOC) -Z unstable-options --emit=invocation-specific --output $(INVOCATION_ONLY) --resource-suffix=-xxx --theme y.css --extend-css z.css x.rs
-	[ -e $(INVOCATION_ONLY)/search-index-xxx.js ]
-	[ -e $(INVOCATION_ONLY)/settings.html ]
-	[ -e $(INVOCATION_ONLY)/x/all.html ]
-	[ -e $(INVOCATION_ONLY)/x/index.html ]
-	[ -e $(INVOCATION_ONLY)/theme-xxx.css ] # generated from z.css
-	! [ -e $(INVOCATION_ONLY)/storage-xxx.js ]
-	! [ -e $(INVOCATION_ONLY)/SourceSerif4-It.ttf.woff2 ]
-
-	# FIXME: this probably shouldn't have a suffix
-	[ -e $(INVOCATION_ONLY)/y-xxx.css ]
-	# FIXME: this is technically incorrect (see `write_shared`)
-	! [ -e $(INVOCATION_ONLY)/main-xxx.js ]
-
-toolchain-only:
-	$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources --output $(TOOLCHAIN_ONLY) --resource-suffix=-xxx --extend-css z.css x.rs
-	[ -e $(TOOLCHAIN_ONLY)/static.files/storage-*.js ]
-	[ -e $(TOOLCHAIN_ONLY)/static.files/SourceSerif4-It-*.ttf.woff2 ]
-	! [ -e $(TOOLCHAIN_ONLY)/search-index-xxx.js ]
-	! [ -e $(TOOLCHAIN_ONLY)/x/index.html ]
-	! [ -e $(TOOLCHAIN_ONLY)/theme.css ]
-
-	[ -e $(TOOLCHAIN_ONLY)/static.files/main-*.js ]
-	! [ -e $(TOOLCHAIN_ONLY)/y-xxx.css ]
-
-all-shared:
-	$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources,unversioned-shared-resources --output $(ALL_SHARED) --resource-suffix=-xxx --extend-css z.css x.rs
-	[ -e $(ALL_SHARED)/static.files/storage-*.js ]
-	[ -e $(ALL_SHARED)/static.files/SourceSerif4-It-*.ttf.woff2 ]
-	! [ -e $(ALL_SHARED)/search-index-xxx.js ]
-	! [ -e $(ALL_SHARED)/settings.html ]
-	! [ -e $(ALL_SHARED)/x ]
-	! [ -e $(ALL_SHARED)/src ]
-	! [ -e $(ALL_SHARED)/theme.css ]
-
-	[ -e $(ALL_SHARED)/static.files/main-*.js ]
-	! [ -e $(ALL_SHARED)/y-xxx.css ]
diff --git a/tests/run-make/emit-shared-files/rmake.rs b/tests/run-make/emit-shared-files/rmake.rs
new file mode 100644
index 00000000000..33c12310246
--- /dev/null
+++ b/tests/run-make/emit-shared-files/rmake.rs
@@ -0,0 +1,102 @@
+// This test checks the functionality of one of rustdoc's unstable options,
+// the ability to specify emit restrictions with `--emit`.
+// `invocation-only` should only emit crate-specific files.
+// `toolchain-only` should only emit toolchain-specific files.
+// `all-shared` should only emit files that can be shared between crates.
+// See https://github.com/rust-lang/rust/pull/83478
+
+use run_make_support::{has_extension, has_prefix, rustdoc, shallow_find_files};
+use std::path::Path;
+
+fn main() {
+    rustdoc()
+        .arg("-Zunstable-options")
+        .arg("--emit=invocation-specific")
+        .output("invocation-only")
+        .arg("--resource-suffix=-xxx")
+        .args(&["--theme", "y.css"])
+        .args(&["--extend-css", "z.css"])
+        .input("x.rs")
+        .run();
+    assert!(Path::new("invocation-only/search-index-xxx.js").exists());
+    assert!(Path::new("invocation-only/settings.html").exists());
+    assert!(Path::new("invocation-only/x/all.html").exists());
+    assert!(Path::new("invocation-only/x/index.html").exists());
+    assert!(Path::new("invocation-only/theme-xxx.css").exists()); // generated from z.css
+    assert!(!Path::new("invocation-only/storage-xxx.js").exists());
+    assert!(!Path::new("invocation-only/SourceSerif4-It.ttf.woff2").exists());
+    // FIXME: this probably shouldn't have a suffix
+    assert!(Path::new("invocation-only/y-xxx.css").exists());
+    // FIXME: this is technically incorrect (see `write_shared`)
+    assert!(!Path::new("invocation-only/main-xxx.js").exists());
+
+    rustdoc()
+        .arg("-Zunstable-options")
+        .arg("--emit=toolchain-shared-resources")
+        .output("toolchain-only")
+        .arg("--resource-suffix=-xxx")
+        .args(&["--extend-css", "z.css"])
+        .input("x.rs")
+        .run();
+    assert_eq!(
+        shallow_find_files("toolchain-only/static.files", |path| {
+            has_prefix(path, "storage-") && has_extension(path, "js")
+        })
+        .len(),
+        1
+    );
+    assert_eq!(
+        shallow_find_files("toolchain-only/static.files", |path| {
+            has_prefix(path, "SourceSerif4-It-") && has_extension(path, "woff2")
+        })
+        .len(),
+        1
+    );
+    assert_eq!(
+        shallow_find_files("toolchain-only/static.files", |path| {
+            has_prefix(path, "main-") && has_extension(path, "js")
+        })
+        .len(),
+        1
+    );
+    assert!(!Path::new("toolchain-only/search-index-xxx.js").exists());
+    assert!(!Path::new("toolchain-only/x/index.html").exists());
+    assert!(!Path::new("toolchain-only/theme.css").exists());
+    assert!(!Path::new("toolchain-only/y-xxx.css").exists());
+
+    rustdoc()
+        .arg("-Zunstable-options")
+        .arg("--emit=toolchain-shared-resources,unversioned-shared-resources")
+        .output("all-shared")
+        .arg("--resource-suffix=-xxx")
+        .args(&["--extend-css", "z.css"])
+        .input("x.rs")
+        .run();
+    assert_eq!(
+        shallow_find_files("all-shared/static.files", |path| {
+            has_prefix(path, "storage-") && has_extension(path, "js")
+        })
+        .len(),
+        1
+    );
+    assert_eq!(
+        shallow_find_files("all-shared/static.files", |path| {
+            has_prefix(path, "SourceSerif4-It-") && has_extension(path, "woff2")
+        })
+        .len(),
+        1
+    );
+    assert!(!Path::new("all-shared/search-index-xxx.js").exists());
+    assert!(!Path::new("all-shared/settings.html").exists());
+    assert!(!Path::new("all-shared/x").exists());
+    assert!(!Path::new("all-shared/src").exists());
+    assert!(!Path::new("all-shared/theme.css").exists());
+    assert_eq!(
+        shallow_find_files("all-shared/static.files", |path| {
+            has_prefix(path, "main-") && has_extension(path, "js")
+        })
+        .len(),
+        1
+    );
+    assert!(!Path::new("all-shared/y-xxx.css").exists());
+}
diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs
index c6bfae4cc01..62b8479c328 100644
--- a/tests/run-make/inaccessible-temp-dir/rmake.rs
+++ b/tests/run-make/inaccessible-temp-dir/rmake.rs
@@ -13,13 +13,18 @@
 // use a directory with non-existing parent like `/does-not-exist/output`.
 // See https://github.com/rust-lang/rust/issues/66530
 
+//@ ignore-riscv64
+// FIXME: The riscv64gc-gnu build container runs as root, and can always write
+// into `inaccessible/tmp`. Ideally, the riscv64-gnu docker container
+// would use a non-root user, but this leads to issues with
+// `mkfs.ext4 -d`, as well as mounting a loop device for the rootfs.
 //@ ignore-arm
 // Reason: linker error on `armhf-gnu`
 //@ ignore-windows
 // Reason: `set_readonly` has no effect on directories
 // and does not prevent modification.
 
-use run_make_support::{fs_wrapper, rustc, target, test_while_readonly};
+use run_make_support::{fs_wrapper, rustc, test_while_readonly};
 
 fn main() {
     // Create an inaccessible directory.
@@ -28,7 +33,6 @@ fn main() {
         // Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one,
         // so that it can't create `tmp`.
         rustc()
-            .target(&target())
             .input("program.rs")
             .arg("-Ztemps-dir=inaccessible/tmp")
             .run_fail()
diff --git a/tests/run-make/issue-47384/lib.rs b/tests/run-make/include-all-symbols-linking/lib.rs
index 99508bcdaf3..99508bcdaf3 100644
--- a/tests/run-make/issue-47384/lib.rs
+++ b/tests/run-make/include-all-symbols-linking/lib.rs
diff --git a/tests/run-make/issue-47384/linker.ld b/tests/run-make/include-all-symbols-linking/linker.ld
index 2e70acab3f4..2e70acab3f4 100644
--- a/tests/run-make/issue-47384/linker.ld
+++ b/tests/run-make/include-all-symbols-linking/linker.ld
diff --git a/tests/run-make/issue-47384/main.rs b/tests/run-make/include-all-symbols-linking/main.rs
index 02572632517..02572632517 100644
--- a/tests/run-make/issue-47384/main.rs
+++ b/tests/run-make/include-all-symbols-linking/main.rs
diff --git a/tests/run-make/include-all-symbols-linking/rmake.rs b/tests/run-make/include-all-symbols-linking/rmake.rs
new file mode 100644
index 00000000000..77fd71ab20d
--- /dev/null
+++ b/tests/run-make/include-all-symbols-linking/rmake.rs
@@ -0,0 +1,31 @@
+// Linkers treat archives differently from object files: all object files participate in linking,
+// while archives will only participate in linking if they can satisfy at least one undefined
+// reference (version scripts doesn't count). This causes `#[no_mangle]` or `#[used]` items to
+// be ignored by the linker, and since they never participate in the linking, using `KEEP` in the
+// linker scripts can't keep them either. This causes #47384. After the fix in #95604, this test
+// checks that these symbols and sections successfully appear in the output dynamic library.
+// See https://github.com/rust-lang/rust/pull/95604
+// See https://github.com/rust-lang/rust/issues/47384
+
+//@ only-linux
+// Reason: differences in object file formats on OSX and Windows
+// causes errors in the llvm_objdump step
+
+use run_make_support::{dynamic_lib_name, llvm_objdump, llvm_readobj, rustc};
+
+fn main() {
+    rustc().crate_type("lib").input("lib.rs").run();
+    rustc().crate_type("cdylib").link_args("-Tlinker.ld").input("main.rs").run();
+    // Ensure `#[used]` and `KEEP`-ed section is there
+    llvm_objdump()
+        .arg("--full-contents")
+        .arg("--section=.static")
+        .input(dynamic_lib_name("main"))
+        .run();
+    // Ensure `#[no_mangle]` symbol is there
+    llvm_readobj()
+        .arg("--symbols")
+        .input(dynamic_lib_name("main"))
+        .run()
+        .assert_stdout_contains("bar");
+}
diff --git a/tests/run-make/include_bytes_deps/input.bin b/tests/run-make/include-bytes-deps/input.bin
index cd0875583aa..cd0875583aa 100644
--- a/tests/run-make/include_bytes_deps/input.bin
+++ b/tests/run-make/include-bytes-deps/input.bin
diff --git a/tests/run-make/include_bytes_deps/input.md b/tests/run-make/include-bytes-deps/input.md
index 2a19b7405f7..2a19b7405f7 100644
--- a/tests/run-make/include_bytes_deps/input.md
+++ b/tests/run-make/include-bytes-deps/input.md
diff --git a/tests/run-make/include_bytes_deps/input.txt b/tests/run-make/include-bytes-deps/input.txt
index cd0875583aa..cd0875583aa 100644
--- a/tests/run-make/include_bytes_deps/input.txt
+++ b/tests/run-make/include-bytes-deps/input.txt
diff --git a/tests/run-make/include_bytes_deps/main.rs b/tests/run-make/include-bytes-deps/main.rs
index 2fd55699d44..2fd55699d44 100644
--- a/tests/run-make/include_bytes_deps/main.rs
+++ b/tests/run-make/include-bytes-deps/main.rs
diff --git a/tests/run-make/include-bytes-deps/rmake.rs b/tests/run-make/include-bytes-deps/rmake.rs
new file mode 100644
index 00000000000..ea371ddae56
--- /dev/null
+++ b/tests/run-make/include-bytes-deps/rmake.rs
@@ -0,0 +1,13 @@
+// include_bytes! and include_str! in `main.rs`
+// should register the included file as of #24423,
+// and this test checks that this is still the case.
+// See https://github.com/rust-lang/rust/pull/24423
+
+use run_make_support::{invalid_utf8_contains, rustc};
+
+fn main() {
+    rustc().emit("dep-info").input("main.rs").run();
+    invalid_utf8_contains("main.d", "input.txt");
+    invalid_utf8_contains("main.d", "input.bin");
+    invalid_utf8_contains("main.d", "input.md");
+}
diff --git a/tests/run-make/include_bytes_deps/Makefile b/tests/run-make/include_bytes_deps/Makefile
deleted file mode 100644
index 696dfd207bb..00000000000
--- a/tests/run-make/include_bytes_deps/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-include ../tools.mk
-
-# ignore-freebsd
-
-all:
-	$(RUSTC) --emit dep-info main.rs
-	$(CGREP) "input.txt" "input.bin" "input.md" < $(TMPDIR)/main.d
diff --git a/tests/run-make/intrinsic-unreachable/Makefile b/tests/run-make/intrinsic-unreachable/Makefile
deleted file mode 100644
index ff9cc57098c..00000000000
--- a/tests/run-make/intrinsic-unreachable/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-
-# needs-asm-support
-# ignore-windows-msvc
-#
-# Because of Windows exception handling, the code is not necessarily any shorter.
-# https://github.com/llvm-mirror/llvm/commit/64b2297786f7fd6f5fa24cdd4db0298fbf211466
-
-all:
-	$(RUSTC) -O --emit asm exit-ret.rs
-	$(RUSTC) -O --emit asm exit-unreachable.rs
-	test `wc -l < $(TMPDIR)/exit-unreachable.s` -lt `wc -l < $(TMPDIR)/exit-ret.s`
diff --git a/tests/run-make/intrinsic-unreachable/rmake.rs b/tests/run-make/intrinsic-unreachable/rmake.rs
new file mode 100644
index 00000000000..7e78c8288b8
--- /dev/null
+++ b/tests/run-make/intrinsic-unreachable/rmake.rs
@@ -0,0 +1,20 @@
+// intrinsics::unreachable tells the compiler that a certain point in the code
+// is not reachable by any means, which enables some useful optimizations.
+// In this test, exit-unreachable contains this instruction and exit-ret does not,
+// which means the emitted artifacts should be shorter in length.
+// See https://github.com/rust-lang/rust/pull/16970
+
+//@ needs-asm-support
+//@ ignore-windows
+// Reason: Because of Windows exception handling, the code is not necessarily any shorter.
+
+use run_make_support::{fs_wrapper, rustc};
+
+fn main() {
+    rustc().opt().emit("asm").input("exit-ret.rs").run();
+    rustc().opt().emit("asm").input("exit-unreachable.rs").run();
+    assert!(
+        fs_wrapper::read_to_string("exit-unreachable.s").lines().count()
+            < fs_wrapper::read_to_string("exit-ret.s").lines().count()
+    );
+}
diff --git a/tests/run-make/issue-37839/Makefile b/tests/run-make/issue-37839/Makefile
deleted file mode 100644
index 6bad27b7bdc..00000000000
--- a/tests/run-make/issue-37839/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) a.rs && $(RUSTC) b.rs
-	$(BARE_RUSTC) c.rs -L dependency=$(TMPDIR) --extern b=$(TMPDIR)/libb.rlib \
-		--out-dir=$(TMPDIR)
diff --git a/tests/run-make/issue-40535/Makefile b/tests/run-make/issue-40535/Makefile
deleted file mode 100644
index 155c8825214..00000000000
--- a/tests/run-make/issue-40535/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-include ../tools.mk
-
-# The ICE occurred in the following situation:
-# * `foo` declares `extern crate bar, baz`, depends only on `bar` (forgetting `baz` in `Cargo.toml`)
-# * `bar` declares and depends on `extern crate baz`
-# * All crates built in metadata-only mode (`cargo check`)
-all:
-	# cc https://github.com/rust-lang/rust/issues/40623
-	$(RUSTC) baz.rs --emit=metadata
-	$(RUSTC) bar.rs --emit=metadata --extern baz=$(TMPDIR)/libbaz.rmeta
-	$(RUSTC) foo.rs --emit=metadata --extern bar=$(TMPDIR)/libbar.rmeta 2>&1 | \
-		$(CGREP) -v "unexpectedly panicked"
-	# ^ Succeeds if it doesn't find the ICE message
diff --git a/tests/run-make/issue-47384/Makefile b/tests/run-make/issue-47384/Makefile
deleted file mode 100644
index afc77cb275a..00000000000
--- a/tests/run-make/issue-47384/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-
-# only-linux
-# ignore-cross-compile
-
-all: main.rs
-	$(RUSTC) --crate-type lib lib.rs
-	$(RUSTC) --crate-type cdylib -Clink-args="-Tlinker.ld" main.rs
-	# Ensure `#[used]` and `KEEP`-ed section is there
-	objdump -s -j".static" $(TMPDIR)/libmain.so
-	# Ensure `#[no_mangle]` symbol is there
-	nm $(TMPDIR)/libmain.so | $(CGREP) bar
diff --git a/tests/run-make/llvm-ident/Makefile b/tests/run-make/llvm-ident/Makefile
deleted file mode 100644
index e583e6018e0..00000000000
--- a/tests/run-make/llvm-ident/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-include ../tools.mk
-
-# only-linux
-
-all:
-	# `-Ccodegen-units=16 -Copt-level=2` is used here to trigger thin LTO
-	# across codegen units to test deduplication of the named metadata
-	# (see `LLVMRustPrepareThinLTOImport` for details).
-	echo 'fn main(){}' | $(RUSTC) - --emit=link,obj -Csave-temps -Ccodegen-units=16 -Copt-level=2 --target=$(TARGET)
-
-	# `llvm-dis` is used here since `--emit=llvm-ir` does not emit LLVM IR
-	# for temporary outputs.
-	"$(LLVM_BIN_DIR)"/llvm-dis $(TMPDIR)/*.bc
-
-	# Check LLVM IR files (including temporary outputs) have `!llvm.ident`
-	# named metadata, reusing the related codegen test.
-	set -e; for f in $(TMPDIR)/*.ll; do \
-		$(LLVM_FILECHECK) --input-file $$f ../../codegen/llvm-ident.rs; \
-	done
diff --git a/tests/run-make/llvm-ident/rmake.rs b/tests/run-make/llvm-ident/rmake.rs
new file mode 100644
index 00000000000..9699d0579f6
--- /dev/null
+++ b/tests/run-make/llvm-ident/rmake.rs
@@ -0,0 +1,35 @@
+//@ only-linux
+//@ ignore-cross-compile
+
+use run_make_support::llvm::llvm_bin_dir;
+use run_make_support::{
+    cmd, env_var, has_extension, llvm_filecheck, rustc, shallow_find_files, source_root,
+};
+
+fn main() {
+    // `-Ccodegen-units=16 -Copt-level=2` is used here to trigger thin LTO
+    // across codegen units to test deduplication of the named metadata
+    // (see `LLVMRustPrepareThinLTOImport` for details).
+    rustc()
+        .emit("link,obj")
+        .arg("-")
+        .arg("-Csave-temps")
+        .codegen_units(16)
+        .opt_level("2")
+        .target(&env_var("TARGET"))
+        .stdin("fn main(){}")
+        .run();
+
+    // `llvm-dis` is used here since `--emit=llvm-ir` does not emit LLVM IR
+    // for temporary outputs.
+    let files = shallow_find_files(".", |path| has_extension(path, "bc"));
+    cmd(llvm_bin_dir().join("llvm-dis")).args(files).run();
+
+    // Check LLVM IR files (including temporary outputs) have `!llvm.ident`
+    // named metadata, reusing the related codegen test.
+    let llvm_ident_path = source_root().join("tests/codegen/llvm-ident.rs");
+    let files = shallow_find_files(".", |path| has_extension(path, "ll"));
+    for file in files {
+        llvm_filecheck().input_file(file).arg(&llvm_ident_path).run();
+    }
+}
diff --git a/tests/run-make/issue-40535/bar.rs b/tests/run-make/metadata-only-crate-no-ice/bar.rs
index b02b28f59d9..b02b28f59d9 100644
--- a/tests/run-make/issue-40535/bar.rs
+++ b/tests/run-make/metadata-only-crate-no-ice/bar.rs
diff --git a/tests/run-make/issue-40535/baz.rs b/tests/run-make/metadata-only-crate-no-ice/baz.rs
index 83be6e807e0..83be6e807e0 100644
--- a/tests/run-make/issue-40535/baz.rs
+++ b/tests/run-make/metadata-only-crate-no-ice/baz.rs
diff --git a/tests/run-make/issue-40535/foo.rs b/tests/run-make/metadata-only-crate-no-ice/foo.rs
index 27020266425..27020266425 100644
--- a/tests/run-make/issue-40535/foo.rs
+++ b/tests/run-make/metadata-only-crate-no-ice/foo.rs
diff --git a/tests/run-make/metadata-only-crate-no-ice/rmake.rs b/tests/run-make/metadata-only-crate-no-ice/rmake.rs
new file mode 100644
index 00000000000..e6f852fca41
--- /dev/null
+++ b/tests/run-make/metadata-only-crate-no-ice/rmake.rs
@@ -0,0 +1,14 @@
+// In a dependency hierarchy, metadata-only crates could cause an Internal
+// Compiler Error (ICE) due to a compiler bug - not correctly fetching sources for
+// metadata-only crates. This test is a minimal reproduction of a program that triggered
+// this bug, and checks that no ICE occurs.
+// See https://github.com/rust-lang/rust/issues/40535
+
+use run_make_support::rustc;
+
+fn main() {
+    rustc().input("baz.rs").emit("metadata").run();
+    rustc().input("bar.rs").emit("metadata").extern_("baz", "libbaz.rmeta").run();
+    // There should be no internal compiler error.
+    rustc().input("foo.rs").emit("metadata").extern_("bar", "libbaz.rmeta").run();
+}
diff --git a/tests/run-make/msvc-opt-minsize/Makefile b/tests/run-make/msvc-opt-minsize/Makefile
deleted file mode 100644
index 32e6e28018f..00000000000
--- a/tests/run-make/msvc-opt-minsize/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) foo.rs -Copt-level=z 2>&1
-	$(call RUN,foo)
diff --git a/tests/run-make/msvc-opt-minsize/foo.rs b/tests/run-make/msvc-opt-minsize/foo.rs
deleted file mode 100644
index 3f5496c08ee..00000000000
--- a/tests/run-make/msvc-opt-minsize/foo.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-#![feature(test)]
-extern crate test;
-
-fn foo(x: i32, y: i32) -> i64 {
-    (x + y) as i64
-}
-
-#[inline(never)]
-fn bar() {
-    let _f = Box::new(0);
-    // This call used to trigger an LLVM bug in opt-level z where the base
-    // pointer gets corrupted, see issue #45034
-    let y: fn(i32, i32) -> i64 = test::black_box(foo);
-    test::black_box(y(1, 2));
-}
-
-fn main() {
-    bar();
-}
diff --git a/tests/run-make/optimization-remarks-dir-pgo/Makefile b/tests/run-make/optimization-remarks-dir-pgo/Makefile
deleted file mode 100644
index 57ffd6e70f0..00000000000
--- a/tests/run-make/optimization-remarks-dir-pgo/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# needs-profiler-support
-# ignore-cross-compile
-
-include ../tools.mk
-
-PROFILE_DIR=$(TMPDIR)/profiles
-
-check_hotness:
-	$(RUSTC) -Cprofile-generate="$(TMPDIR)"/profdata -O foo.rs -o$(TMPDIR)/foo
-	$(TMPDIR)/foo
-	"$(LLVM_BIN_DIR)"/llvm-profdata merge \
-		-o "$(TMPDIR)"/merged.profdata \
-		"$(TMPDIR)"/profdata/*.profraw
-	$(RUSTC) -Cprofile-use=$(TMPDIR)/merged.profdata -O foo.rs -Cremark=all -Zremark-dir=$(PROFILE_DIR)
-
-	# Check that PGO hotness is included in the remark files
-	cat $(PROFILE_DIR)/*.opt.yaml | $(CGREP) -e "Hotness"
diff --git a/tests/run-make/optimization-remarks-dir-pgo/rmake.rs b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs
new file mode 100644
index 00000000000..228c43cc5f1
--- /dev/null
+++ b/tests/run-make/optimization-remarks-dir-pgo/rmake.rs
@@ -0,0 +1,41 @@
+// This test checks the -Zremark-dir flag, which writes LLVM
+// optimization remarks to the YAML format. When using PGO (Profile
+// Guided Optimization), the Hotness attribute should be included in
+// the output remark files.
+// See https://github.com/rust-lang/rust/pull/114439
+
+//@ needs-profiler-support
+//@ ignore-cross-compile
+
+use run_make_support::{
+    has_extension, has_prefix, invalid_utf8_contains, llvm_profdata, run, rustc, shallow_find_files,
+};
+
+fn main() {
+    rustc().profile_generate("profdata").opt().input("foo.rs").output("foo").run();
+    run("foo");
+    // The profdata filename is a long sequence of numbers, fetch it by prefix and extension
+    // to keep the test working even if the filename changes.
+    let profdata_files = shallow_find_files("profdata", |path| {
+        has_prefix(path, "default") && has_extension(path, "profraw")
+    });
+    let profdata_file = profdata_files.get(0).unwrap();
+    llvm_profdata().merge().output("merged.profdata").input(profdata_file).run();
+    rustc()
+        .profile_use("merged.profdata")
+        .opt()
+        .input("foo.rs")
+        .arg("-Cremark=all")
+        .arg("-Zremark-dir=profiles")
+        .run();
+    // Check that PGO hotness is included in the remark files
+    let remark_files = shallow_find_files("profiles", |path| {
+        has_prefix(path, "foo") && has_extension(path, "yaml")
+    });
+    assert!(!remark_files.is_empty());
+    for file in remark_files {
+        if !file.to_str().unwrap().contains("codegen") {
+            invalid_utf8_contains(file, "Hotness")
+        };
+    }
+}
diff --git a/tests/run-make/optimization-remarks-dir/Makefile b/tests/run-make/optimization-remarks-dir/Makefile
deleted file mode 100644
index a8342c8ad14..00000000000
--- a/tests/run-make/optimization-remarks-dir/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-
-PROFILE_DIR=$(TMPDIR)/profiles
-
-all: check_inline check_filter
-
-check_inline:
-	$(RUSTC) -O foo.rs --crate-type=lib -Cremark=all -Zremark-dir=$(PROFILE_DIR)
-	cat $(PROFILE_DIR)/*.opt.yaml | $(CGREP) -e "inline"
-check_filter:
-	$(RUSTC) -O foo.rs --crate-type=lib -Cremark=foo -Zremark-dir=$(PROFILE_DIR)
-	cat $(PROFILE_DIR)/*.opt.yaml | $(CGREP) -e -v "inline"
diff --git a/tests/run-make/optimization-remarks-dir/rmake.rs b/tests/run-make/optimization-remarks-dir/rmake.rs
new file mode 100644
index 00000000000..afcb8c3e3eb
--- /dev/null
+++ b/tests/run-make/optimization-remarks-dir/rmake.rs
@@ -0,0 +1,39 @@
+// In this test, the function `bar` has #[inline(never)] and the function `foo`
+// does not. This test outputs LLVM optimization remarks twice - first for all
+// functions (including `bar`, and the `inline` mention), and then for only `foo`
+// (should not have the `inline` mention).
+// See https://github.com/rust-lang/rust/pull/113040
+
+use run_make_support::{
+    has_extension, has_prefix, invalid_utf8_contains, invalid_utf8_not_contains, not_contains,
+    rustc, shallow_find_files,
+};
+
+fn main() {
+    rustc()
+        .opt()
+        .input("foo.rs")
+        .crate_type("lib")
+        .arg("-Cremark=all")
+        .arg("-Zremark-dir=profiles_all")
+        .run();
+    let all_remark_files = shallow_find_files("profiles_all", |path| {
+        has_prefix(path, "foo") && has_extension(path, "yaml") && not_contains(path, "codegen")
+    });
+    for file in all_remark_files {
+        invalid_utf8_contains(file, "inline")
+    }
+    rustc()
+        .opt()
+        .input("foo.rs")
+        .crate_type("lib")
+        .arg("-Cremark=foo")
+        .arg("-Zremark-dir=profiles_foo")
+        .run();
+    let foo_remark_files = shallow_find_files("profiles_foo", |path| {
+        has_prefix(path, "foo") && has_extension(path, "yaml")
+    });
+    for file in foo_remark_files {
+        invalid_utf8_not_contains(file, "inline")
+    }
+}
diff --git a/tests/run-make/output-type-permutations/Makefile b/tests/run-make/output-type-permutations/Makefile
deleted file mode 100644
index 035033b9fdd..00000000000
--- a/tests/run-make/output-type-permutations/Makefile
+++ /dev/null
@@ -1,147 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) foo.rs --crate-type=rlib,dylib,staticlib
-	$(call REMOVE_RLIBS,bar)
-	$(call REMOVE_DYLIBS,bar)
-	rm $(call STATICLIB,bar)
-	rm -f $(TMPDIR)/{lib,}bar.{dll.exp,dll.lib,pdb,dll.a}
-	# Check that $(TMPDIR) is empty.
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --crate-type=bin
-	rm $(TMPDIR)/$(call BIN,bar)
-	rm -f $(TMPDIR)/bar.pdb
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link
-	rm $(TMPDIR)/bar.ll
-	rm $(TMPDIR)/bar.bc
-	rm $(TMPDIR)/bar.s
-	rm $(TMPDIR)/bar.o
-	rm $(TMPDIR)/$(call BIN,bar)
-	rm -f $(TMPDIR)/bar.pdb
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --emit asm -o $(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --emit asm=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --emit=asm=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --emit llvm-bc -o $(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --emit llvm-bc=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --emit=llvm-bc=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --emit llvm-ir -o $(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --emit=llvm-ir=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --emit obj -o $(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --emit obj=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --emit=obj=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --emit link -o $(TMPDIR)/$(call BIN,foo)
-	rm $(TMPDIR)/$(call BIN,foo)
-	$(RUSTC) foo.rs --emit link=$(TMPDIR)/$(call BIN,foo)
-	rm $(TMPDIR)/$(call BIN,foo)
-	$(RUSTC) foo.rs --emit=link=$(TMPDIR)/$(call BIN,foo)
-	rm $(TMPDIR)/$(call BIN,foo)
-	rm -f $(TMPDIR)/foo.pdb
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --crate-type=rlib --emit link=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --crate-type=rlib --emit=link=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --crate-type=dylib -o $(TMPDIR)/$(call BIN,foo)
-	rm $(TMPDIR)/$(call BIN,foo)
-	$(RUSTC) foo.rs --crate-type=dylib --emit link=$(TMPDIR)/$(call BIN,foo)
-	rm $(TMPDIR)/$(call BIN,foo)
-	$(RUSTC) foo.rs --crate-type=dylib --emit=link=$(TMPDIR)/$(call BIN,foo)
-	rm $(TMPDIR)/$(call BIN,foo)
-	rm -f $(TMPDIR)/{lib,}foo.{dll.exp,dll.lib,pdb,dll.a,exe.a}
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] || (ls -1 $(TMPDIR) && exit 1)
-
-	$(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --crate-type=staticlib --emit link=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	$(RUSTC) foo.rs --crate-type=staticlib --emit=link=$(TMPDIR)/foo
-	rm $(TMPDIR)/foo
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --crate-type=bin -o $(TMPDIR)/$(call BIN,foo)
-	rm $(TMPDIR)/$(call BIN,foo)
-	$(RUSTC) foo.rs --crate-type=bin --emit link=$(TMPDIR)/$(call BIN,foo)
-	rm $(TMPDIR)/$(call BIN,foo)
-	$(RUSTC) foo.rs --crate-type=bin --emit=link=$(TMPDIR)/$(call BIN,foo)
-	rm $(TMPDIR)/$(call BIN,foo)
-	rm -f $(TMPDIR)/foo.pdb
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/ir \
-			--emit link \
-			--crate-type=rlib
-	rm $(TMPDIR)/ir
-	rm $(TMPDIR)/libbar.rlib
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --emit asm=$(TMPDIR)/asm \
-			--emit llvm-ir=$(TMPDIR)/ir \
-			--emit llvm-bc=$(TMPDIR)/bc \
-		        --emit obj=$(TMPDIR)/obj \
-			--emit link=$(TMPDIR)/link \
-			--crate-type=staticlib
-	rm $(TMPDIR)/asm
-	rm $(TMPDIR)/ir
-	rm $(TMPDIR)/bc
-	rm $(TMPDIR)/obj
-	rm $(TMPDIR)/link
-	$(RUSTC) foo.rs --emit=asm=$(TMPDIR)/asm \
-			--emit llvm-ir=$(TMPDIR)/ir \
-			--emit=llvm-bc=$(TMPDIR)/bc \
-		        --emit obj=$(TMPDIR)/obj \
-			--emit=link=$(TMPDIR)/link \
-			--crate-type=staticlib
-	rm $(TMPDIR)/asm
-	rm $(TMPDIR)/ir
-	rm $(TMPDIR)/bc
-	rm $(TMPDIR)/obj
-	rm $(TMPDIR)/link
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
-
-	$(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link --crate-type=staticlib
-	rm $(TMPDIR)/bar.ll
-	rm $(TMPDIR)/bar.s
-	rm $(TMPDIR)/bar.o
-	rm $(call STATICLIB,bar)
-	mv $(TMPDIR)/bar.bc $(TMPDIR)/foo.bc
-	# Don't check that the $(TMPDIR) is empty - we left `foo.bc` for later
-	# comparison.
-
-	$(RUSTC) foo.rs --emit=llvm-bc,link --crate-type=rlib
-	cmp $(TMPDIR)/foo.bc $(TMPDIR)/bar.bc
-	rm $(TMPDIR)/bar.bc
-	rm $(TMPDIR)/foo.bc
-	$(call REMOVE_RLIBS,bar)
-	[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs
new file mode 100644
index 00000000000..1d1637a744e
--- /dev/null
+++ b/tests/run-make/output-type-permutations/rmake.rs
@@ -0,0 +1,542 @@
+// In 2014, rustc's output flags were reworked to be a lot more modular.
+// This test uses these output flags in an expansive variety of combinations
+// and syntax styles, checking that compilation is successful and that output
+// files are exactly what is expected, no more, no less.
+// See https://github.com/rust-lang/rust/pull/12020
+
+use run_make_support::{
+    bin_name, dynamic_lib_name, filename_not_in_denylist, fs_wrapper, rust_lib_name, rustc,
+    shallow_find_files, static_lib_name,
+};
+use std::path::PathBuf;
+
+// Each test takes 4 arguments:
+// `must_exist`: output files which must be found - if any are absent, the test fails
+// `can_exist`: optional output files which will not trigger a failure
+// `dir`: the name of the directory where the test happens
+// `rustc_invocation`: the rustc command being tested
+// Any unexpected output files not listed in `must_exist` or `can_exist` will cause a failure.
+fn assert_expected_output_files(expectations: Expectations, rustc_invocation: impl Fn()) {
+    let Expectations { expected_files: must_exist, allowed_files: can_exist, test_dir: dir } =
+        expectations;
+
+    fs_wrapper::create_dir(&dir);
+    rustc_invocation();
+    for file in must_exist {
+        fs_wrapper::remove_file(PathBuf::from(&dir).join(&file));
+    }
+    let actual_output_files =
+        shallow_find_files(dir, |path| filename_not_in_denylist(path, &can_exist));
+    if !&actual_output_files.is_empty() {
+        dbg!(&actual_output_files);
+        panic!("unexpected output artifacts detected");
+    }
+}
+
+struct Expectations {
+    /// Output files which must be found. The test fails if any are absent.
+    expected_files: Vec<String>,
+    /// Allowed output files which will not trigger a failure.
+    allowed_files: Vec<String>,
+    /// Name of the directory where the test happens.
+    test_dir: String,
+}
+
+macro_rules! s {
+    ( $( $x:expr ),* ) => {
+        {
+            let mut temp_vec = Vec::new();
+            $(
+                temp_vec.push($x.to_string());
+            )*
+            temp_vec
+        }
+    };
+}
+
+fn main() {
+    let bin_foo = bin_name("foo");
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![
+                static_lib_name("bar"),
+                dynamic_lib_name("bar"),
+                rust_lib_name("bar")
+            ],
+            allowed_files: s![
+                "libbar.dll.exp",
+                "libbar.dll.lib",
+                "libbar.pdb",
+                "libbar.dll.a",
+                "libbar.exe.a",
+                "bar.dll.exp",
+                "bar.dll.lib",
+                "bar.pdb",
+                "bar.dll.a",
+                "bar.exe.a"
+            ],
+            test_dir: "three-crates".to_string(),
+        },
+        || {
+            rustc()
+                .input("foo.rs")
+                .out_dir("three-crates")
+                .crate_type("rlib,dylib,staticlib")
+                .run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![bin_name("bar")],
+            allowed_files: s!["bar.pdb"],
+            test_dir: "bin-crate".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").crate_type("bin").out_dir("bin-crate").run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["bar.ll", "bar.bc", "bar.s", "bar.o", bin_name("bar")],
+            allowed_files: s!["bar.pdb"],
+            test_dir: "all-emit".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("asm,llvm-ir,llvm-bc,obj,link").out_dir("all-emit").run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "asm-emit".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("asm").output("asm-emit/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "asm-emit2".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("asm=asm-emit2/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "asm-emit3".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").arg("--emit=asm=asm-emit3/foo").run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "llvm-ir-emit".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("llvm-ir").output("llvm-ir-emit/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "llvm-ir-emit2".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("llvm-ir=llvm-ir-emit2/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "llvm-ir-emit3".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").arg("--emit=llvm-ir=llvm-ir-emit3/foo").run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "llvm-bc-emit".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("llvm-bc").output("llvm-bc-emit/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "llvm-bc-emit2".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("llvm-bc=llvm-bc-emit2/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "llvm-bc-emit3".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").arg("--emit=llvm-bc=llvm-bc-emit3/foo").run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "obj-emit".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("obj").output("obj-emit/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "obj-emit2".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("obj=obj-emit2/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "obj-emit3".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").arg("--emit=obj=obj-emit3/foo").run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![&bin_foo],
+            allowed_files: s!["foo.pdb"],
+            test_dir: "link-emit".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit("link").output("link-emit/".to_owned() + &bin_foo).run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![&bin_foo],
+            allowed_files: s!["foo.pdb"],
+            test_dir: "link-emit2".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").emit(&format!("link=link-emit2/{bin_foo}")).run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![&bin_foo],
+            allowed_files: s!["foo.pdb"],
+            test_dir: "link-emit3".to_string(),
+        },
+        || {
+            rustc().input("foo.rs").arg(&format!("--emit=link=link-emit3/{bin_foo}")).run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "rlib".to_string(),
+        },
+        || {
+            rustc().crate_type("rlib").input("foo.rs").output("rlib/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "rlib2".to_string(),
+        },
+        || {
+            rustc().crate_type("rlib").input("foo.rs").emit("link=rlib2/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "rlib3".to_string(),
+        },
+        || {
+            rustc().crate_type("rlib").input("foo.rs").arg("--emit=link=rlib3/foo").run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![bin_foo],
+            allowed_files: s![
+                "libfoo.dll.exp",
+                "libfoo.dll.lib",
+                "libfoo.pdb",
+                "libfoo.dll.a",
+                "libfoo.exe.a",
+                "foo.dll.exp",
+                "foo.dll.lib",
+                "foo.pdb",
+                "foo.dll.a",
+                "foo.exe.a"
+            ],
+            test_dir: "dylib".to_string(),
+        },
+        || {
+            rustc()
+                .crate_type("dylib")
+                .input("foo.rs")
+                .output("dylib/".to_owned() + &bin_foo)
+                .run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![bin_foo],
+            allowed_files: s![
+                "libfoo.dll.exp",
+                "libfoo.dll.lib",
+                "libfoo.pdb",
+                "libfoo.dll.a",
+                "libfoo.exe.a",
+                "foo.dll.exp",
+                "foo.dll.lib",
+                "foo.pdb",
+                "foo.dll.a",
+                "foo.exe.a"
+            ],
+            test_dir: "dylib2".to_string(),
+        },
+        || {
+            rustc()
+                .crate_type("dylib")
+                .input("foo.rs")
+                .emit(&format!("link=dylib2/{bin_foo}"))
+                .run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![bin_foo],
+            allowed_files: s![
+                "libfoo.dll.exp",
+                "libfoo.dll.lib",
+                "libfoo.pdb",
+                "libfoo.dll.a",
+                "libfoo.exe.a",
+                "foo.dll.exp",
+                "foo.dll.lib",
+                "foo.pdb",
+                "foo.dll.a",
+                "foo.exe.a"
+            ],
+            test_dir: "dylib3".to_string(),
+        },
+        || {
+            rustc()
+                .crate_type("dylib")
+                .input("foo.rs")
+                .arg(&format!("--emit=link=dylib3/{bin_foo}"))
+                .run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "staticlib".to_string(),
+        },
+        || {
+            rustc().crate_type("staticlib").input("foo.rs").output("staticlib/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "staticlib2".to_string(),
+        },
+        || {
+            rustc().crate_type("staticlib").input("foo.rs").emit("link=staticlib2/foo").run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["foo"],
+            allowed_files: s![],
+            test_dir: "staticlib3".to_string(),
+        },
+        || {
+            rustc().crate_type("staticlib").input("foo.rs").arg("--emit=link=staticlib3/foo").run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![bin_foo],
+            allowed_files: s!["foo.pdb"],
+            test_dir: "bincrate".to_string(),
+        },
+        || {
+            rustc()
+                .crate_type("bin")
+                .input("foo.rs")
+                .output("bincrate/".to_owned() + &bin_foo)
+                .run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![bin_foo],
+            allowed_files: s!["foo.pdb"],
+            test_dir: "bincrate2".to_string(),
+        },
+        || {
+            rustc()
+                .crate_type("bin")
+                .input("foo.rs")
+                .emit(&format!("link=bincrate2/{bin_foo}"))
+                .run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s![bin_foo],
+            allowed_files: s!["foo.pdb"],
+            test_dir: "bincrate3".to_string(),
+        },
+        || {
+            rustc()
+                .crate_type("bin")
+                .input("foo.rs")
+                .arg(&format!("--emit=link=bincrate3/{bin_foo}"))
+                .run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["ir", rust_lib_name("bar")],
+            allowed_files: s![],
+            test_dir: "rlib-ir".to_string(),
+        },
+        || {
+            rustc()
+                .input("foo.rs")
+                .emit("llvm-ir=rlib-ir/ir")
+                .emit("link")
+                .crate_type("rlib")
+                .out_dir("rlib-ir")
+                .run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["ir", "asm", "bc", "obj", "link"],
+            allowed_files: s![],
+            test_dir: "staticlib-all".to_string(),
+        },
+        || {
+            rustc()
+                .input("foo.rs")
+                .emit("asm=staticlib-all/asm")
+                .emit("llvm-ir=staticlib-all/ir")
+                .emit("llvm-bc=staticlib-all/bc")
+                .emit("obj=staticlib-all/obj")
+                .emit("link=staticlib-all/link")
+                .crate_type("staticlib")
+                .run();
+        },
+    );
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["ir", "asm", "bc", "obj", "link"],
+            allowed_files: s![],
+            test_dir: "staticlib-all2".to_string(),
+        },
+        || {
+            rustc()
+                .input("foo.rs")
+                .arg("--emit=asm=staticlib-all2/asm")
+                .arg("--emit")
+                .arg("llvm-ir=staticlib-all2/ir")
+                .arg("--emit=llvm-bc=staticlib-all2/bc")
+                .arg("--emit")
+                .arg("obj=staticlib-all2/obj")
+                .arg("--emit=link=staticlib-all2/link")
+                .crate_type("staticlib")
+                .run();
+        },
+    );
+
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["bar.ll", "bar.s", "bar.o", static_lib_name("bar")],
+            allowed_files: s!["bar.bc"], // keep this one for the next test
+            test_dir: "staticlib-all3".to_string(),
+        },
+        || {
+            rustc()
+                .input("foo.rs")
+                .emit("asm,llvm-ir,llvm-bc,obj,link")
+                .crate_type("staticlib")
+                .out_dir("staticlib-all3")
+                .run();
+        },
+    );
+
+    // the .bc file from the previous test should be equivalent to this one, despite the difference
+    // in crate type
+    assert_expected_output_files(
+        Expectations {
+            expected_files: s!["bar.bc", rust_lib_name("bar"), "foo.bc"],
+            allowed_files: s![],
+            test_dir: "rlib-emits".to_string(),
+        },
+        || {
+            fs_wrapper::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc");
+            rustc()
+                .input("foo.rs")
+                .emit("llvm-bc,link")
+                .crate_type("rlib")
+                .out_dir("rlib-emits")
+                .run();
+            assert_eq!(
+                fs_wrapper::read("rlib-emits/foo.bc"),
+                fs_wrapper::read("rlib-emits/bar.bc")
+            );
+        },
+    );
+}
diff --git a/tests/run-make/pass-linker-flags-flavor/Makefile b/tests/run-make/pass-linker-flags-flavor/Makefile
deleted file mode 100644
index 1bb05d0f974..00000000000
--- a/tests/run-make/pass-linker-flags-flavor/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# only-linux
-
-include ../tools.mk
-
-all:
-	$(RUSTC) empty.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*-Wl,a1.*l2.*-Wl,a2.*d1.*-Wl,a3'
-	$(RUSTC) empty.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg:+verbatim=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*-Wl,a2.*d1.*-Wl,a3'
-	$(RUSTC) empty.rs -Z unstable-options -C linker-flavor=ld -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*"a2".*d1.*"a3"'
-	$(RUSTC) attribute.rs -Z unstable-options -C linker-flavor=gnu-cc --print link-args | $(CGREP) -e 'l1.*-Wl,a1.*l2.*-Wl,a2.*d1.*-Wl,a3'
-	$(RUSTC) --cfg 'feature="verbatim"' attribute.rs -Z unstable-options -C linker-flavor=gnu-cc --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*-Wl,a2.*d1.*-Wl,a3'
-	$(RUSTC) attribute.rs -C linker-flavor=ld --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*"a2".*d1.*"a3"'
diff --git a/tests/run-make/pass-linker-flags-flavor/rmake.rs b/tests/run-make/pass-linker-flags-flavor/rmake.rs
new file mode 100644
index 00000000000..e36d68cc884
--- /dev/null
+++ b/tests/run-make/pass-linker-flags-flavor/rmake.rs
@@ -0,0 +1,84 @@
+// Setting the linker flavor as a C compiler should cause the output of the -l flags to be
+// prefixed by -Wl, except when a flag is requested to be verbatim. A bare linker (ld) should
+// never cause prefixes to appear in the output. This test checks this ruleset twice, once with
+// explicit flags and then with those flags passed inside the rust source code.
+// See https://github.com/rust-lang/rust/pull/118202
+
+//@ only-linux
+// Reason: the `gnu-cc` linker is only available on linux
+
+use run_make_support::{regex, rustc};
+
+fn main() {
+    let out_gnu = rustc()
+        .input("empty.rs")
+        .linker_flavor("gnu-cc")
+        .arg("-Zunstable-options")
+        .arg("-lstatic=l1")
+        .arg("-llink-arg=a1")
+        .arg("-lstatic=l2")
+        .arg("-llink-arg=a2")
+        .arg("-ldylib=d1")
+        .arg("-llink-arg=a3")
+        .print("link-args")
+        .run_unchecked()
+        .stdout_utf8();
+    let out_gnu_verbatim = rustc()
+        .input("empty.rs")
+        .linker_flavor("gnu-cc")
+        .arg("-Zunstable-options")
+        .arg("-lstatic=l1")
+        .arg("-llink-arg:+verbatim=a1")
+        .arg("-lstatic=l2")
+        .arg("-llink-arg=a2")
+        .arg("-ldylib=d1")
+        .arg("-llink-arg=a3")
+        .print("link-args")
+        .run_unchecked()
+        .stdout_utf8();
+    let out_ld = rustc()
+        .input("empty.rs")
+        .linker_flavor("ld")
+        .arg("-Zunstable-options")
+        .arg("-lstatic=l1")
+        .arg("-llink-arg=a1")
+        .arg("-lstatic=l2")
+        .arg("-llink-arg=a2")
+        .arg("-ldylib=d1")
+        .arg("-llink-arg=a3")
+        .print("link-args")
+        .run_unchecked()
+        .stdout_utf8();
+    let out_att_gnu = rustc()
+        .arg("-Zunstable-options")
+        .linker_flavor("gnu-cc")
+        .input("attribute.rs")
+        .print("link-args")
+        .run_unchecked()
+        .stdout_utf8();
+    let out_att_gnu_verbatim = rustc()
+        .cfg(r#"feature="verbatim""#)
+        .arg("-Zunstable-options")
+        .linker_flavor("gnu-cc")
+        .input("attribute.rs")
+        .print("link-args")
+        .run_unchecked()
+        .stdout_utf8();
+    let out_att_ld = rustc()
+        .linker_flavor("ld")
+        .input("attribute.rs")
+        .print("link-args")
+        .run_unchecked()
+        .stdout_utf8();
+
+    let no_verbatim = regex::Regex::new("l1.*-Wl,a1.*l2.*-Wl,a2.*d1.*-Wl,a3").unwrap();
+    let one_verbatim = regex::Regex::new(r#"l1.*"a1".*l2.*-Wl,a2.*d1.*-Wl,a3"#).unwrap();
+    let ld = regex::Regex::new(r#"l1.*"a1".*l2.*"a2".*d1.*"a3""#).unwrap();
+
+    assert!(no_verbatim.is_match(&out_gnu));
+    assert!(no_verbatim.is_match(&out_att_gnu));
+    assert!(one_verbatim.is_match(&out_gnu_verbatim));
+    assert!(one_verbatim.is_match(&out_att_gnu_verbatim));
+    assert!(ld.is_match(&out_ld));
+    assert!(ld.is_match(&out_att_ld));
+}
diff --git a/tests/run-make/pass-linker-flags-from-dep/Makefile b/tests/run-make/pass-linker-flags-from-dep/Makefile
deleted file mode 100644
index 48b3b26ce81..00000000000
--- a/tests/run-make/pass-linker-flags-from-dep/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-
-all:
-	# Build deps
-	$(RUSTC) native_dep_1.rs --crate-type=staticlib
-	$(RUSTC) native_dep_2.rs --crate-type=staticlib
-	$(RUSTC) rust_dep_flag.rs -l static:-bundle=native_dep_1 -l link-arg=some_flag -l static:-bundle=native_dep_2 --crate-type=lib -Z unstable-options
-	$(RUSTC) rust_dep_attr.rs --crate-type=lib
-
-	# Check sequence of linker args
-	$(RUSTC) main.rs --extern lib=$(TMPDIR)/librust_dep_flag.rlib --crate-type=bin --print link-args | $(CGREP) -e 'native_dep_1.*some_flag.*native_dep_2'
-	$(RUSTC) main.rs --extern lib=$(TMPDIR)/librust_dep_attr.rlib --crate-type=bin --print link-args | $(CGREP) -e 'native_dep_1.*some_flag.*native_dep_2'
diff --git a/tests/run-make/pass-linker-flags-from-dep/rmake.rs b/tests/run-make/pass-linker-flags-from-dep/rmake.rs
new file mode 100644
index 00000000000..4b8e0486e14
--- /dev/null
+++ b/tests/run-make/pass-linker-flags-from-dep/rmake.rs
@@ -0,0 +1,43 @@
+// A similar test to pass-linker-flags, testing that the `-l link-arg` flag
+// respects the order relative to other `-l` flags, but this time, the flags
+// are passed on the compilation of a dependency. This test checks that the
+// downstream compiled binary contains the linker arguments of the dependency,
+// and in the correct order.
+// See https://github.com/rust-lang/rust/issues/99427
+
+use run_make_support::{regex, rust_lib_name, rustc};
+
+fn main() {
+    // Build dependencies
+    rustc().input("native_dep_1.rs").crate_type("staticlib").run();
+    rustc().input("native_dep_2.rs").crate_type("staticlib").run();
+    rustc()
+        .input("rust_dep_flag.rs")
+        .arg("-lstatic:-bundle=native_dep_1")
+        .arg("-llink-arg=some_flag")
+        .arg("-lstatic:-bundle=native_dep_2")
+        .crate_type("lib")
+        .arg("-Zunstable-options")
+        .run();
+    rustc().input("rust_dep_attr.rs").crate_type("lib").run();
+
+    // Check sequence of linker arguments
+    let out_flag = rustc()
+        .input("main.rs")
+        .extern_("lib", rust_lib_name("rust_dep_flag"))
+        .crate_type("bin")
+        .print("link-args")
+        .run_unchecked()
+        .stdout_utf8();
+    let out_attr = rustc()
+        .input("main.rs")
+        .extern_("lib", rust_lib_name("rust_dep_attr"))
+        .crate_type("bin")
+        .print("link-args")
+        .run_unchecked()
+        .stdout_utf8();
+
+    let re = regex::Regex::new("native_dep_1.*some_flag.*native_dep_2").unwrap();
+    assert!(re.is_match(&out_flag));
+    assert!(re.is_match(&out_attr));
+}
diff --git a/tests/run-make/pass-linker-flags/Makefile b/tests/run-make/pass-linker-flags/Makefile
deleted file mode 100644
index 226943e93bd..00000000000
--- a/tests/run-make/pass-linker-flags/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTC) empty.rs -Z unstable-options -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*a1.*l2.*a2.*d1.*a3'
-	$(RUSTC) attribute.rs --print link-args | $(CGREP) -e 'l1.*a1.*l2.*a2.*d1.*a3'
diff --git a/tests/run-make/pass-linker-flags/rmake.rs b/tests/run-make/pass-linker-flags/rmake.rs
new file mode 100644
index 00000000000..de69567a6e6
--- /dev/null
+++ b/tests/run-make/pass-linker-flags/rmake.rs
@@ -0,0 +1,28 @@
+// This test checks the proper function of `-l link-arg=NAME`, which, unlike
+// -C link-arg, is supposed to guarantee that the order relative to other -l
+// options will be respected. In this test, compilation fails (because none of the
+// link arguments like `a1` exist), but it is still checked if the output contains the
+// link arguments in the exact order they were passed in. `attribute.rs` is a variant
+// of the test where the flags are defined in the rust file itself.
+// See https://github.com/rust-lang/rust/issues/99427
+
+use run_make_support::{regex, rustc};
+
+fn main() {
+    let out = rustc()
+        .input("empty.rs")
+        .arg("-Zunstable-options")
+        .arg("-lstatic=l1")
+        .arg("-llink-arg=a1")
+        .arg("-lstatic=l2")
+        .arg("-llink-arg=a2")
+        .arg("-ldylib=d1")
+        .arg("-llink-arg=a3")
+        .print("link-args")
+        .run_unchecked()
+        .stdout_utf8();
+    let out2 = rustc().input("attribute.rs").print("link-args").run_unchecked().stdout_utf8();
+    let re = regex::Regex::new("l1.*a1.*l2.*a2.*d1.*a3").unwrap();
+    assert!(re.is_match(&out));
+    assert!(re.is_match(&out2));
+}
diff --git a/tests/run-make/pgo-gen/Makefile b/tests/run-make/pgo-gen/Makefile
deleted file mode 100644
index c1d456986fb..00000000000
--- a/tests/run-make/pgo-gen/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# needs-profiler-support
-# ignore-cross-compile
-
-include ../tools.mk
-
-COMPILE_FLAGS=-g -Cprofile-generate="$(TMPDIR)"
-
-all:
-	$(RUSTC) $(COMPILE_FLAGS) test.rs
-	$(call RUN,test) || exit 1
-	[ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1)
diff --git a/tests/run-make/pgo-gen/rmake.rs b/tests/run-make/pgo-gen/rmake.rs
new file mode 100644
index 00000000000..ad2f6388e8f
--- /dev/null
+++ b/tests/run-make/pgo-gen/rmake.rs
@@ -0,0 +1,18 @@
+// -C profile-generate, when used with rustc, is supposed to output
+// profile files (.profraw) after running a binary to analyze how the compiler
+// optimizes code. This test checks that these files are generated.
+// See https://github.com/rust-lang/rust/pull/48346
+
+//@ needs-profiler-support
+//@ ignore-cross-compile
+
+use run_make_support::{cwd, has_extension, has_prefix, run, rustc, shallow_find_files};
+
+fn main() {
+    rustc().arg("-g").profile_generate(cwd()).input("test.rs").run();
+    run("test");
+    let profraw_files = shallow_find_files(cwd(), |path| {
+        has_prefix(path, "default") && has_extension(path, "profraw")
+    });
+    assert!(!profraw_files.is_empty(), "no .profraw file generated");
+}
diff --git a/tests/run-make/pgo-use/Makefile b/tests/run-make/pgo-use/Makefile
deleted file mode 100644
index 92098a4019c..00000000000
--- a/tests/run-make/pgo-use/Makefile
+++ /dev/null
@@ -1,43 +0,0 @@
-# needs-profiler-support
-# ignore-cross-compile
-
-include ../tools.mk
-
-# This test makes sure that PGO profiling data leads to cold functions being
-# marked as `cold` and hot functions with `inlinehint`.
-# The test program contains an `if` were actual execution only ever takes the
-# `else` branch. Accordingly, we expect the function that is never called to
-# be marked as cold.
-#
-# Disable the pre-inlining pass (i.e. a pass that does some inlining before
-# it adds the profiling instrumentation). Disabling this pass leads to
-# rather predictable IR which we need for this test to be stable.
-
-COMMON_FLAGS=-Copt-level=2 -Ccodegen-units=1 -Cllvm-args=-disable-preinline
-
-ifeq ($(UNAME),Darwin)
-# macOS does not have the `tac` command, but `tail -r` does the same thing
-TAC := tail -r
-else
-# some other platforms don't support the `-r` flag for `tail`, so use `tac`
-TAC := tac
-endif
-
-all:
-	# Compile the test program with instrumentation
-	$(RUSTC) $(COMMON_FLAGS) -Cprofile-generate="$(TMPDIR)" main.rs
-	# Run it in order to generate some profiling data
-	$(call RUN,main some-argument) || exit 1
-	# Postprocess the profiling data so it can be used by the compiler
-	"$(LLVM_BIN_DIR)"/llvm-profdata merge \
-		-o "$(TMPDIR)"/merged.profdata \
-		"$(TMPDIR)"/default_*.profraw
-	# Compile the test program again, making use of the profiling data
-	$(RUSTC) $(COMMON_FLAGS) -Cprofile-use="$(TMPDIR)"/merged.profdata --emit=llvm-ir main.rs
-	# Check that the generate IR contains some things that we expect
-	#
-	# We feed the file into LLVM FileCheck tool *in reverse* so that we see the
-	# line with the function name before the line with the function attributes.
-	# FileCheck only supports checking that something matches on the next line,
-	# but not if something matches on the previous line.
-	$(TAC) "$(TMPDIR)"/main.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt
diff --git a/tests/run-make/pgo-use/rmake.rs b/tests/run-make/pgo-use/rmake.rs
new file mode 100644
index 00000000000..0f76aff80d0
--- /dev/null
+++ b/tests/run-make/pgo-use/rmake.rs
@@ -0,0 +1,55 @@
+// This test makes sure that PGO profiling data leads to cold functions being
+// marked as `cold` and hot functions with `inlinehint`.
+// The test program contains an `if` where actual execution only ever takes the
+// `else` branch. Accordingly, we expect the function that is never called to
+// be marked as cold.
+// See https://github.com/rust-lang/rust/pull/60262
+
+//@ needs-profiler-support
+//@ ignore-cross-compile
+
+use run_make_support::{
+    cwd, fs_wrapper, has_extension, has_prefix, llvm_filecheck, llvm_profdata, run_with_args,
+    rustc, shallow_find_files,
+};
+
+fn main() {
+    // Compile the test program with instrumentation
+    // Disable the pre-inlining pass (i.e. a pass that does some inlining before
+    // it adds the profiling instrumentation). Disabling this pass leads to
+    // rather predictable IR which we need for this test to be stable.
+    rustc()
+        .opt_level("2")
+        .codegen_units(1)
+        .arg("-Cllvm-args=-disable-preinline")
+        .profile_generate(cwd())
+        .input("main.rs")
+        .run();
+    // Run it in order to generate some profiling data
+    run_with_args("main", &["some-argument"]);
+    // Postprocess the profiling data so it can be used by the compiler
+    let profraw_files = shallow_find_files(cwd(), |path| {
+        has_prefix(path, "default") && has_extension(path, "profraw")
+    });
+    let profraw_file = profraw_files.get(0).unwrap();
+    llvm_profdata().merge().output("merged.profdata").input(profraw_file).run();
+    // Compile the test program again, making use of the profiling data
+    rustc()
+        .opt_level("2")
+        .codegen_units(1)
+        .arg("-Cllvm-args=-disable-preinline")
+        .profile_use("merged.profdata")
+        .emit("llvm-ir")
+        .input("main.rs")
+        .run();
+    // Check that the generate IR contains some things that we expect.
+    // We feed the file into LLVM FileCheck tool *with its lines reversed* so that we see the
+    // line with the function name before the line with the function attributes.
+    // FileCheck only supports checking that something matches on the next line,
+    // but not if something matches on the previous line.
+    let ir = fs_wrapper::read_to_string("main.ll");
+    let lines: Vec<_> = ir.lines().rev().collect();
+    let mut reversed_ir = lines.join("\n");
+    reversed_ir.push('\n');
+    llvm_filecheck().patterns("filecheck-patterns.txt").stdin(reversed_ir.as_bytes()).run();
+}
diff --git a/tests/run-make/issue-37839/a.rs b/tests/run-make/proc-macro-three-crates/a.rs
index b5dffac3ff6..b5dffac3ff6 100644
--- a/tests/run-make/issue-37839/a.rs
+++ b/tests/run-make/proc-macro-three-crates/a.rs
diff --git a/tests/run-make/issue-37839/b.rs b/tests/run-make/proc-macro-three-crates/b.rs
index 067f47c1b7a..067f47c1b7a 100644
--- a/tests/run-make/issue-37839/b.rs
+++ b/tests/run-make/proc-macro-three-crates/b.rs
diff --git a/tests/run-make/issue-37839/c.rs b/tests/run-make/proc-macro-three-crates/c.rs
index 4c7ce01b6a0..4c7ce01b6a0 100644
--- a/tests/run-make/issue-37839/c.rs
+++ b/tests/run-make/proc-macro-three-crates/c.rs
diff --git a/tests/run-make/proc-macro-three-crates/rmake.rs b/tests/run-make/proc-macro-three-crates/rmake.rs
new file mode 100644
index 00000000000..d3735540fdd
--- /dev/null
+++ b/tests/run-make/proc-macro-three-crates/rmake.rs
@@ -0,0 +1,20 @@
+// A compiler bug caused the following issue:
+// If a crate A depends on crate B, and crate B
+// depends on crate C, and crate C contains a procedural
+// macro, compiling crate A would fail.
+// This was fixed in #37846, and this test checks
+// that this bug does not make a resurgence.
+
+use run_make_support::{bare_rustc, cwd, rust_lib_name, rustc};
+
+fn main() {
+    rustc().input("a.rs").run();
+    rustc().input("b.rs").run();
+    let curr_dir = cwd().display().to_string();
+    bare_rustc()
+        .input("c.rs")
+        .arg(format!("-Ldependency={curr_dir}"))
+        .extern_("b", cwd().join(rust_lib_name("b")))
+        .out_dir(cwd())
+        .run();
+}
diff --git a/tests/run-make/profile/Makefile b/tests/run-make/profile/Makefile
deleted file mode 100644
index 7919b18ba74..00000000000
--- a/tests/run-make/profile/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# needs-profiler-support
-# ignore-cross-compile
-
-include ../tools.mk
-
-all:
-	$(RUSTC) -g -Z profile test.rs
-	$(call RUN,test) || exit 1
-	[ -e "$(TMPDIR)/test.gcno" ] || (echo "No .gcno file"; exit 1)
-	[ -e "$(TMPDIR)/test.gcda" ] || (echo "No .gcda file"; exit 1)
-	$(RUSTC) -g -Z profile -Z profile-emit=$(TMPDIR)/abc/abc.gcda test.rs
-	$(call RUN,test) || exit 1
-	[ -e "$(TMPDIR)/abc/abc.gcda" ] || (echo "gcda file not emitted to defined path"; exit 1)
diff --git a/tests/run-make/profile/rmake.rs b/tests/run-make/profile/rmake.rs
new file mode 100644
index 00000000000..8d41978baec
--- /dev/null
+++ b/tests/run-make/profile/rmake.rs
@@ -0,0 +1,22 @@
+// This test revolves around the rustc flag -Z profile, which should
+// generate a .gcno file (initial profiling information) as well
+// as a .gcda file (branch counters). The path where these are emitted
+// should also be configurable with -Z profile-emit. This test checks
+// that the files are produced, and then that the latter flag is respected.
+// See https://github.com/rust-lang/rust/pull/42433
+
+//@ ignore-cross-compile
+//@ needs-profiler-support
+
+use run_make_support::{run, rustc};
+use std::path::Path;
+
+fn main() {
+    rustc().arg("-g").arg("-Zprofile").input("test.rs").run();
+    run("test");
+    assert!(Path::new("test.gcno").exists(), "no .gcno file");
+    assert!(Path::new("test.gcda").exists(), "no .gcda file");
+    rustc().arg("-g").arg("-Zprofile").arg("-Zprofile-emit=abc/abc.gcda").input("test.rs").run();
+    run("test");
+    assert!(Path::new("abc/abc.gcda").exists(), "gcda file not emitted to defined path");
+}
diff --git a/tests/run-make/rlib-chain/Makefile b/tests/run-make/rlib-chain/Makefile
deleted file mode 100644
index 7a1f887fa52..00000000000
--- a/tests/run-make/rlib-chain/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) m1.rs
-	$(RUSTC) m2.rs
-	$(RUSTC) m3.rs
-	$(RUSTC) m4.rs
-	$(call RUN,m4)
-	rm $(TMPDIR)/*lib
-	$(call RUN,m4)
diff --git a/tests/run-make/rlib-chain/rmake.rs b/tests/run-make/rlib-chain/rmake.rs
new file mode 100644
index 00000000000..0947262bf62
--- /dev/null
+++ b/tests/run-make/rlib-chain/rmake.rs
@@ -0,0 +1,23 @@
+// In this test, m4 depends on m3, which depends on m2, which depends on m1.
+// Even though dependencies are chained like this and there is no direct mention
+// of m1 or m2 in m4.rs, compilation and execution should still succeed. Unlike
+// the dylib-chain test, rlibs do not contain upstream dependencies, and removing
+// the libraries still allows m4 to successfully execute.
+// See https://github.com/rust-lang/rust/issues/10434
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{fs_wrapper, run, rust_lib_name, rustc};
+
+fn main() {
+    rustc().input("m1.rs").run();
+    rustc().input("m2.rs").run();
+    rustc().input("m3.rs").run();
+    rustc().input("m4.rs").run();
+    run("m4");
+    fs_wrapper::remove_file(rust_lib_name("m1"));
+    fs_wrapper::remove_file(rust_lib_name("m2"));
+    fs_wrapper::remove_file(rust_lib_name("m3"));
+    run("m4");
+}
diff --git a/tests/run-make/rmeta-preferred/Makefile b/tests/run-make/rmeta-preferred/Makefile
deleted file mode 100644
index 3bf12cced29..00000000000
--- a/tests/run-make/rmeta-preferred/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# Test that using rlibs and rmeta dep crates work together. Specifically, that
-# there can be both an rmeta and an rlib file and rustc will prefer the rmeta
-# file.
-#
-# This behavior is simply making sure this doesn't accidentally change; in this
-# case we want to make sure that the rlib isn't being used as that would cause
-# bugs in -Zbinary-dep-depinfo (see #68298).
-
-all:
-	$(RUSTC) rmeta_aux.rs --crate-type=rlib --emit link,metadata
-	$(RUSTC) lib.rs --crate-type=rlib --emit dep-info -Zbinary-dep-depinfo
-	$(CGREP) "librmeta_aux.rmeta" < $(TMPDIR)/lib.d
-	$(CGREP) -v "librmeta_aux.rlib" < $(TMPDIR)/lib.d
diff --git a/tests/run-make/rmeta-preferred/rmake.rs b/tests/run-make/rmeta-preferred/rmake.rs
new file mode 100644
index 00000000000..09cba06e2f5
--- /dev/null
+++ b/tests/run-make/rmeta-preferred/rmake.rs
@@ -0,0 +1,18 @@
+// This test compiles `lib.rs`'s dependency, `rmeta_aux.rs`, as both an rlib
+// and an rmeta crate. By default, rustc should give the metadata crate (rmeta)
+// precedence over the rust-lib (rlib). This test inspects the contents of the binary
+// and that the correct (rmeta) crate was used.
+// rlibs being preferred could indicate a resurgence of the -Zbinary-dep-depinfo bug
+// seen in #68298.
+// See https://github.com/rust-lang/rust/pull/37681
+
+//@ ignore-cross-compile
+
+use run_make_support::{invalid_utf8_contains, invalid_utf8_not_contains, rustc};
+
+fn main() {
+    rustc().input("rmeta_aux.rs").crate_type("rlib").emit("link,metadata").run();
+    rustc().input("lib.rs").crate_type("rlib").emit("dep-info").arg("-Zbinary-dep-depinfo").run();
+    invalid_utf8_contains("lib.d", "librmeta_aux.rmeta");
+    invalid_utf8_not_contains("lib.d", "librmeta_aux.rlib");
+}
diff --git a/tests/run-make/rustdoc-io-error/rmake.rs b/tests/run-make/rustdoc-io-error/rmake.rs
index d60e4438e6f..69afea40162 100644
--- a/tests/run-make/rustdoc-io-error/rmake.rs
+++ b/tests/run-make/rustdoc-io-error/rmake.rs
@@ -6,8 +6,13 @@
 // permissions so that it is not writable. We have to take special care to set
 // the permissions back to normal so that it's able to be deleted later.
 
+//@ ignore-riscv64
+//@ ignore-arm
+// FIXME: The riscv64gc-gnu and armhf-gnu build containers run as root,
+// and can always write into `inaccessible/tmp`. Ideally, these docker
+// containers would use a non-root user, but this leads to issues with
+// `mkfs.ext4 -d`, as well as mounting a loop device for the rootfs.
 //@ ignore-windows - the `set_readonly` functions doesn't work on folders.
-//@ ignore-arm - weird file perms on armhf-gnu
 
 use run_make_support::{path, rustdoc};
 use std::fs;
diff --git a/tests/run-make/sepcomp-cci-copies/Makefile b/tests/run-make/sepcomp-cci-copies/Makefile
deleted file mode 100644
index df289d0b0b1..00000000000
--- a/tests/run-make/sepcomp-cci-copies/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-
-# Check that cross-crate inlined items are inlined in all compilation units
-# that refer to them, and not in any other compilation units.
-# Note that we have to pass `-C codegen-units=6` because up to two CGUs may be
-# created for each source module (see `rustc_const_eval::monomorphize::partitioning`).
-
-all:
-	$(RUSTC) cci_lib.rs
-	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=6 \
-		-Z inline-in-all-cgus
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*cci_fn)" -eq "2" ]
diff --git a/tests/run-make/sepcomp-cci-copies/rmake.rs b/tests/run-make/sepcomp-cci-copies/rmake.rs
new file mode 100644
index 00000000000..612a73977fe
--- /dev/null
+++ b/tests/run-make/sepcomp-cci-copies/rmake.rs
@@ -0,0 +1,17 @@
+// Check that cross-crate inlined items are inlined in all compilation units
+// that refer to them, and not in any other compilation units.
+// Note that we have to pass `-C codegen-units=6` because up to two CGUs may be
+// created for each source module (see `rustc_const_eval::monomorphize::partitioning`).
+// See https://github.com/rust-lang/rust/pull/16367
+
+use run_make_support::{
+    count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc,
+    shallow_find_files,
+};
+
+fn main() {
+    rustc().input("cci_lib.rs").run();
+    rustc().input("foo.rs").emit("llvm-ir").codegen_units(6).arg("-Zinline-in-all-cgus").run();
+    let re = regex::Regex::new(r#"define\ .*cci_fn"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 2);
+}
diff --git a/tests/run-make/sepcomp-inlining/Makefile b/tests/run-make/sepcomp-inlining/Makefile
deleted file mode 100644
index 327aeb75e5e..00000000000
--- a/tests/run-make/sepcomp-inlining/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-include ../tools.mk
-
-# Test that #[inline] functions still get inlined across compilation unit
-# boundaries. Compilation should produce three IR files, but only the two
-# compilation units that have a usage of the #[inline] function should
-# contain a definition. Also, the non-#[inline] function should be defined
-# in only one compilation unit.
-
-all:
-	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 \
-		-Z inline-in-all-cgus
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ i32\ .*inlined)" -eq "0" ]
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ]
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ]
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ]
diff --git a/tests/run-make/sepcomp-inlining/rmake.rs b/tests/run-make/sepcomp-inlining/rmake.rs
new file mode 100644
index 00000000000..de7551b9a51
--- /dev/null
+++ b/tests/run-make/sepcomp-inlining/rmake.rs
@@ -0,0 +1,23 @@
+// Test that #[inline] functions still get inlined across compilation unit
+// boundaries. Compilation should produce three IR files, but only the two
+// compilation units that have a usage of the #[inline] function should
+// contain a definition. Also, the non-#[inline] function should be defined
+// in only one compilation unit.
+// See https://github.com/rust-lang/rust/pull/16367
+
+use run_make_support::{
+    count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc,
+    shallow_find_files,
+};
+
+fn main() {
+    rustc().input("foo.rs").emit("llvm-ir").codegen_units(3).arg("-Zinline-in-all-cgus").run();
+    let re = regex::Regex::new(r#"define\ i32\ .*inlined"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 0);
+    let re = regex::Regex::new(r#"define\ internal\ .*inlined"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 2);
+    let re = regex::Regex::new(r#"define\ hidden\ i32\ .*normal"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 1);
+    let re = regex::Regex::new(r#"declare\ hidden\ i32\ .*normal"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 2);
+}
diff --git a/tests/run-make/sepcomp-separate/Makefile b/tests/run-make/sepcomp-separate/Makefile
deleted file mode 100644
index 62cf54a88fb..00000000000
--- a/tests/run-make/sepcomp-separate/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-include ../tools.mk
-
-# Test that separate compilation actually puts code into separate compilation
-# units.  `foo.rs` defines `magic_fn` in three different modules, which should
-# wind up in three different compilation units.
-
-all:
-	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
-	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*magic_fn)" -eq "3" ]
diff --git a/tests/run-make/sepcomp-separate/rmake.rs b/tests/run-make/sepcomp-separate/rmake.rs
new file mode 100644
index 00000000000..6f1d22424b5
--- /dev/null
+++ b/tests/run-make/sepcomp-separate/rmake.rs
@@ -0,0 +1,15 @@
+// Test that separate compilation actually puts code into separate compilation
+// units.  `foo.rs` defines `magic_fn` in three different modules, which should
+// wind up in three different compilation units.
+// See https://github.com/rust-lang/rust/pull/16367
+
+use run_make_support::{
+    count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc,
+    shallow_find_files,
+};
+
+fn main() {
+    rustc().input("foo.rs").emit("llvm-ir").codegen_units(3).run();
+    let re = regex::Regex::new(r#"define\ .*magic_fn"#).unwrap();
+    assert_eq!(count_regex_matches_in_files_with_extension(&re, "ll"), 3);
+}
diff --git a/tests/run-make/static-pie/rmake.rs b/tests/run-make/static-pie/rmake.rs
index 77c5e253bc0..6a92f92328e 100644
--- a/tests/run-make/static-pie/rmake.rs
+++ b/tests/run-make/static-pie/rmake.rs
@@ -51,7 +51,7 @@ fn test(compiler: &str) {
 
     rustc()
         .input("test-aslr.rs")
-        .target(&target())
+        .target(target())
         .linker(compiler)
         .arg("-Clinker-flavor=gcc")
         .arg("-Ctarget-feature=+crt-static")
diff --git a/tests/run-make/target-cpu-native/Makefile b/tests/run-make/target-cpu-native/Makefile
deleted file mode 100644
index eb3ca1e13aa..00000000000
--- a/tests/run-make/target-cpu-native/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-include ../tools.mk
-
-# only-linux
-# only-x86_64
-#
-# I *really* don't want to deal with a cross-platform way to compare file sizes,
-# tests in `make` sort of are awful
-
-all: $(TMPDIR)/out.log
-	# Make sure no warnings about "unknown CPU `native`" were emitted
-	if [ "$$(wc -c $(TMPDIR)/out.log | cut -d' ' -f 1)" = "0" ]; then \
-	  echo no warnings generated; \
-	else \
-	  exit 1; \
-	fi
-
-
-$(TMPDIR)/out.log:
-	$(RUSTC) foo.rs -C target-cpu=native 2>&1 | tee $(TMPDIR)/out.log
-	$(call RUN,foo)
diff --git a/tests/run-make/target-cpu-native/rmake.rs b/tests/run-make/target-cpu-native/rmake.rs
new file mode 100644
index 00000000000..fd5fb6193fe
--- /dev/null
+++ b/tests/run-make/target-cpu-native/rmake.rs
@@ -0,0 +1,14 @@
+// target-cpu is a codegen flag that generates code for the processor of the host machine
+// running the compilation. This test is a sanity test that this flag does not cause any
+// warnings when used, and that binaries produced by it can also be successfully executed.
+// See https://github.com/rust-lang/rust/pull/23238
+
+use run_make_support::{run, rustc};
+
+fn main() {
+    let out = rustc().input("foo.rs").arg("-Ctarget-cpu=native").run().stderr_utf8();
+    run("foo");
+    // There should be zero warnings emitted - the bug would cause "unknown CPU `native`"
+    // to be printed out.
+    assert!(out.is_empty());
+}
diff --git a/tests/run-make/target-specs/Makefile b/tests/run-make/target-specs/Makefile
deleted file mode 100644
index 161b6602185..00000000000
--- a/tests/run-make/target-specs/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-all:
-	$(RUSTC) foo.rs --target=my-awesome-platform.json --crate-type=lib --emit=asm
-	$(CGREP) -v morestack < $(TMPDIR)/foo.s
-	$(RUSTC) foo.rs --target=my-invalid-platform.json 2>&1 | $(CGREP) "Error loading target specification"
-	$(RUSTC) foo.rs --target=my-incomplete-platform.json 2>&1 | $(CGREP) 'Field llvm-target'
-	RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-awesome-platform --crate-type=lib --emit=asm
-	RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-x86_64-unknown-linux-gnu-platform --crate-type=lib --emit=asm
-	$(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json -
-	$(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin'
-	$(RUSTC) foo.rs --target=endianness-mismatch 2>&1 | $(CGREP) '"data-layout" claims architecture is little-endian'
-	$(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib 2>&1 | $(CGREP) 'data-layout for target'
diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs
new file mode 100644
index 00000000000..d2b5f650838
--- /dev/null
+++ b/tests/run-make/target-specs/rmake.rs
@@ -0,0 +1,71 @@
+// Target-specific compilation in rustc used to have case-by-case peculiarities in 2014,
+// with the compiler having redundant target types and unspecific names. An overarching rework
+// in #16156 changed the way the target flag functions, and this test attempts compilation
+// with the target flag's bundle of new features to check that compilation either succeeds while
+// using them correctly, or fails with the right error message when using them improperly.
+// See https://github.com/rust-lang/rust/pull/16156
+
+use run_make_support::{diff, fs_wrapper, rustc};
+
+fn main() {
+    rustc().input("foo.rs").target("my-awesome-platform.json").crate_type("lib").emit("asm").run();
+    assert!(!fs_wrapper::read_to_string("foo.s").contains("morestack"));
+    rustc()
+        .input("foo.rs")
+        .target("my-invalid-platform.json")
+        .run_fail()
+        .assert_stderr_contains("Error loading target specification");
+    rustc()
+        .input("foo.rs")
+        .target("my-incomplete-platform.json")
+        .run_fail()
+        .assert_stderr_contains("Field llvm-target");
+    rustc()
+        .env("RUST_TARGET_PATH", ".")
+        .input("foo.rs")
+        .target("my-awesome-platform")
+        .crate_type("lib")
+        .emit("asm")
+        .run();
+    rustc()
+        .env("RUST_TARGET_PATH", ".")
+        .input("foo.rs")
+        .target("my-x86_64-unknown-linux-gnu-platform")
+        .crate_type("lib")
+        .emit("asm")
+        .run();
+    let test_platform = rustc()
+        .arg("-Zunstable-options")
+        .target("my-awesome-platform.json")
+        .print("target-spec-json")
+        .run()
+        .stdout_utf8();
+    fs_wrapper::create_file("test-platform.json");
+    fs_wrapper::write("test-platform.json", test_platform.as_bytes());
+    let test_platform_2 = rustc()
+        .arg("-Zunstable-options")
+        .target("test-platform.json")
+        .print("target-spec-json")
+        .run()
+        .stdout_utf8();
+    diff()
+        .expected_file("test-platform.json")
+        .actual_text("test-platform-2", test_platform_2)
+        .run();
+    rustc()
+        .input("foo.rs")
+        .target("definitely-not-builtin-target")
+        .run_fail()
+        .assert_stderr_contains("may not set is_builtin");
+    rustc()
+        .input("foo.rs")
+        .target("endianness-mismatch")
+        .run_fail()
+        .assert_stderr_contains(r#""data-layout" claims architecture is little-endian"#);
+    rustc()
+        .input("foo.rs")
+        .target("mismatching-data-layout")
+        .crate_type("lib")
+        .run_fail()
+        .assert_stderr_contains("data-layout for target");
+}
diff --git a/tests/run-make/target-without-atomic-cas/Makefile b/tests/run-make/target-without-atomic-cas/Makefile
deleted file mode 100644
index 451f03d66cd..00000000000
--- a/tests/run-make/target-without-atomic-cas/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-include ../tools.mk
-
-# The target used below doesn't support atomic CAS operations. Verify that's the case
-all:
-	$(RUSTC) --print cfg --target thumbv6m-none-eabi | $(CGREP) -v 'target_has_atomic="ptr"'
diff --git a/tests/run-make/target-without-atomic-cas/rmake.rs b/tests/run-make/target-without-atomic-cas/rmake.rs
new file mode 100644
index 00000000000..c8782b6d1a5
--- /dev/null
+++ b/tests/run-make/target-without-atomic-cas/rmake.rs
@@ -0,0 +1,16 @@
+// ARM Cortex-M are a class of processors supported by the rust compiler. However,
+// they cannot support any atomic features, such as Arc. This test simply prints
+// the configuration details of one Cortex target, and checks that the compiler
+// does not falsely list atomic support.
+// See https://github.com/rust-lang/rust/pull/36874
+
+use run_make_support::rustc;
+
+// The target used below doesn't support atomic CAS operations. Verify that's the case
+fn main() {
+    rustc()
+        .print("cfg")
+        .target("thumbv6m-none-eabi")
+        .run()
+        .assert_stdout_not_contains(r#"target_has_atomic="ptr""#);
+}
diff --git a/tests/run-make/test-harness/Makefile b/tests/run-make/test-harness/Makefile
deleted file mode 100644
index ee8c9294f91..00000000000
--- a/tests/run-make/test-harness/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	# check that #[cfg_attr(..., ignore)] does the right thing.
-	$(RUSTC) --test test-ignore-cfg.rs --cfg ignorecfg
-	$(call RUN,test-ignore-cfg) | $(CGREP) 'shouldnotignore ... ok' 'shouldignore ... ignored'
-	$(call RUN,test-ignore-cfg --quiet) | $(CGREP) -e "^i\.$$"
-	$(call RUN,test-ignore-cfg --quiet) | $(CGREP) -v 'should'
diff --git a/tests/run-make/test-harness/rmake.rs b/tests/run-make/test-harness/rmake.rs
new file mode 100644
index 00000000000..30b3d00f4d1
--- /dev/null
+++ b/tests/run-make/test-harness/rmake.rs
@@ -0,0 +1,25 @@
+// The way test suites run can be modified using configuration flags,
+// ignoring certain tests while running others. This test contains two
+// functions, one which must run and the other which must not. The standard
+// output is checked to verify that the ignore configuration is doing its job,
+// and that output is successfully minimized with the --quiet flag.
+// See https://github.com/rust-lang/rust/commit/f7ebe23ae185991b0fee05b32fbb3e29b89a41bf
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{run, run_with_args, rustc};
+
+fn main() {
+    rustc().arg("--test").input("test-ignore-cfg.rs").cfg("ignorecfg").run();
+    // check that #[cfg_attr(..., ignore)] does the right thing.
+    run("test-ignore-cfg")
+        .assert_stdout_contains("shouldnotignore ... ok")
+        .assert_stdout_contains("shouldignore ... ignored");
+    assert_eq!(
+        // One of the lines is exactly "i."
+        run_with_args("test-ignore-cfg", &["--quiet"]).stdout_utf8().lines().find(|&x| x == "i."),
+        Some("i.")
+    );
+    run_with_args("test-ignore-cfg", &["--quiet"]).assert_stdout_not_contains("should");
+}
diff --git a/tests/run-make/track-path-dep-info/Makefile b/tests/run-make/track-path-dep-info/Makefile
deleted file mode 100644
index 0d6c9b1d2f0..00000000000
--- a/tests/run-make/track-path-dep-info/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-include ../tools.mk
-
-# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC`
-# instead of hardcoding them everywhere they're needed.
-ifeq ($(IS_MUSL_HOST),1)
-ADDITIONAL_ARGS := $(RUSTFLAGS)
-endif
-
-all:
-	# Proc macro
-	$(BARE_RUSTC) $(ADDITIONAL_ARGS) --out-dir $(TMPDIR) macro_def.rs
-	EXISTING_PROC_MACRO_ENV=1 $(RUSTC) --emit dep-info macro_use.rs
-	$(CGREP) "emojis.txt:" < $(TMPDIR)/macro_use.d
diff --git a/tests/run-make/track-path-dep-info/rmake.rs b/tests/run-make/track-path-dep-info/rmake.rs
new file mode 100644
index 00000000000..f108dc66051
--- /dev/null
+++ b/tests/run-make/track-path-dep-info/rmake.rs
@@ -0,0 +1,13 @@
+// This test checks the functionality of `tracked_path::path`, a procedural macro
+// feature that adds a dependency to another file inside the procmacro. In this case,
+// the text file is added through this method, and the test checks that the compilation
+// output successfully added the file as a dependency.
+// See https://github.com/rust-lang/rust/pull/84029
+
+use run_make_support::{fs_wrapper, rustc};
+
+fn main() {
+    rustc().input("macro_def.rs").run();
+    rustc().env("EXISTING_PROC_MACRO_ENV", "1").emit("dep-info").input("macro_use.rs").run();
+    assert!(fs_wrapper::read_to_string("macro_use.d").contains("emojis.txt:"));
+}
diff --git a/tests/run-make/track-pgo-dep-info/Makefile b/tests/run-make/track-pgo-dep-info/Makefile
deleted file mode 100644
index 3afe3662fa7..00000000000
--- a/tests/run-make/track-pgo-dep-info/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-# needs-profiler-support
-
-include ../tools.mk
-
-# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC`
-# instead of hardcoding them everywhere they're needed.
-ifeq ($(IS_MUSL_HOST),1)
-ADDITIONAL_ARGS := $(RUSTFLAGS)
-endif
-
-all:
-	# Generate PGO profiles
-	$(BARE_RUSTC) $(ADDITIONAL_ARGS) -Cprofile-generate=$(TMPDIR)/profiles --out-dir $(TMPDIR) main.rs
-	$(TMPDIR)/main
-
-	# Merge profiles
-	"$(LLVM_BIN_DIR)/llvm-profdata" merge \
-		-o "$(TMPDIR)/merged.profdata" \
-		"$(TMPDIR)/profiles" || exit 1
-
-	# Use the profile
-	$(RUSTC) -Cprofile-use=$(TMPDIR)/merged.profdata --emit dep-info main.rs
-
-	# Check that profile file is in depinfo
-	$(CGREP) "merged.profdata" < $(TMPDIR)/main.d
diff --git a/tests/run-make/track-pgo-dep-info/rmake.rs b/tests/run-make/track-pgo-dep-info/rmake.rs
new file mode 100644
index 00000000000..acfe05cf8ea
--- /dev/null
+++ b/tests/run-make/track-pgo-dep-info/rmake.rs
@@ -0,0 +1,23 @@
+// Emitting dep-info files used to not have any mention of PGO profiles used
+// in compilation, which meant these profiles could be changed without consequence.
+// After changing this in #100801, this test checks that the profile data is successfully
+// included in dep-info emit files.
+// See https://github.com/rust-lang/rust/pull/100801
+
+//@ ignore-cross-compile
+// Reason: the binary is executed
+//@ needs-profiler-support
+
+use run_make_support::{fs_wrapper, llvm_profdata, run, rustc};
+
+fn main() {
+    // Generate the profile-guided-optimization (PGO) profiles
+    rustc().profile_generate("profiles").input("main.rs").run();
+    // Merge the profiles
+    run("main");
+    llvm_profdata().merge().output("merged.profdata").input("profiles").run();
+    // Use the profiles in compilation
+    rustc().profile_use("merged.profdata").emit("dep-info").input("main.rs").run();
+    // Check that the profile file is in the dep-info emit file
+    assert!(fs_wrapper::read_to_string("main.d").contains("merged.profdata"));
+}
diff --git a/tests/run-make/volatile-intrinsics/Makefile b/tests/run-make/volatile-intrinsics/Makefile
deleted file mode 100644
index 5672a045873..00000000000
--- a/tests/run-make/volatile-intrinsics/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	# The tests must pass...
-	$(RUSTC) main.rs
-	$(call RUN,main)
-	# ... and the loads/stores must not be optimized out.
-	$(RUSTC) main.rs --emit=llvm-ir
-	$(CGREP) "load volatile" "store volatile" < $(TMPDIR)/main.ll
diff --git a/tests/run-make/volatile-intrinsics/rmake.rs b/tests/run-make/volatile-intrinsics/rmake.rs
new file mode 100644
index 00000000000..fb9be4bb9ba
--- /dev/null
+++ b/tests/run-make/volatile-intrinsics/rmake.rs
@@ -0,0 +1,18 @@
+//@ ignore-cross-compile
+
+use run_make_support::fs_wrapper::read;
+use run_make_support::{assert_contains, run, rustc};
+
+fn main() {
+    // The tests must pass...
+    rustc().input("main.rs").run();
+    run("main");
+
+    // ... and the loads/stores must not be optimized out.
+    rustc().input("main.rs").emit("llvm-ir").run();
+
+    let raw_llvm_ir = read("main.ll");
+    let llvm_ir = String::from_utf8_lossy(&raw_llvm_ir);
+    assert_contains(&llvm_ir, "load volatile");
+    assert_contains(&llvm_ir, "store volatile");
+}
diff --git a/tests/run-make/wasm-abi/rmake.rs b/tests/run-make/wasm-abi/rmake.rs
index 0fc326babd9..ff12bcd536e 100644
--- a/tests/run-make/wasm-abi/rmake.rs
+++ b/tests/run-make/wasm-abi/rmake.rs
@@ -1,9 +1,8 @@
 //@ only-wasm32-wasip1
 //@ needs-wasmtime
 
-use run_make_support::rustc;
+use run_make_support::{cmd, rustc};
 use std::path::Path;
-use std::process::Command;
 
 fn main() {
     rustc().input("foo.rs").target("wasm32-wasip1").run();
@@ -19,14 +18,12 @@ fn main() {
 }
 
 fn run(file: &Path, method: &str, expected_output: &str) {
-    let output = Command::new("wasmtime")
+    cmd("wasmtime")
         .arg("run")
         .arg("--preload=host=host.wat")
         .arg("--invoke")
         .arg(method)
         .arg(file)
-        .output()
-        .unwrap();
-    assert!(output.status.success());
-    assert_eq!(expected_output, String::from_utf8_lossy(&output.stdout));
+        .run()
+        .assert_stdout_equals(expected_output);
 }
diff --git a/tests/run-make/wasm-exceptions-nostd/Makefile b/tests/run-make/wasm-exceptions-nostd/Makefile
deleted file mode 100644
index 34755ec14b7..00000000000
--- a/tests/run-make/wasm-exceptions-nostd/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-include ../tools.mk
-
-# only-wasm32-bare
-
-# Add a few command line args to make exceptions work
-RUSTC := $(RUSTC) -C llvm-args=-wasm-enable-eh
-RUSTC := $(RUSTC) -C target-feature=+exception-handling
-RUSTC := $(RUSTC) -C panic=unwind
-
-all:
-	$(RUSTC) src/lib.rs --target wasm32-unknown-unknown
-	$(NODE) verify.mjs $(TMPDIR)/lib.wasm
diff --git a/tests/run-make/wasm-exceptions-nostd/rmake.rs b/tests/run-make/wasm-exceptions-nostd/rmake.rs
new file mode 100644
index 00000000000..720ee9909d2
--- /dev/null
+++ b/tests/run-make/wasm-exceptions-nostd/rmake.rs
@@ -0,0 +1,18 @@
+//@ only-wasm32-bare
+
+use std::path::Path;
+
+use run_make_support::{cmd, env_var, rustc};
+
+fn main() {
+    // Add a few command line args to make exceptions work
+    rustc()
+        .input(Path::new("src").join("lib.rs"))
+        .target("wasm32-unknown-unknown")
+        .panic("unwind")
+        .arg("-Cllvm-args=-wasm-enable-eh")
+        .arg("-Ctarget-feature=+exception-handling")
+        .run();
+
+    cmd(&env_var("NODE")).arg("verify.mjs").arg("lib.wasm").run();
+}
diff --git a/tests/run-make/wasm-exceptions-nostd/src/lib.rs b/tests/run-make/wasm-exceptions-nostd/src/lib.rs
index 3ea8797d3a6..ef2f117e01a 100644
--- a/tests/run-make/wasm-exceptions-nostd/src/lib.rs
+++ b/tests/run-make/wasm-exceptions-nostd/src/lib.rs
@@ -5,7 +5,6 @@
 #![feature(core_intrinsics)]
 #![feature(lang_items)]
 #![feature(link_llvm_intrinsics)]
-#![feature(panic_info_message)]
 
 extern crate alloc;
 
diff --git a/tests/run-make/wasm-exceptions-nostd/src/panicking.rs b/tests/run-make/wasm-exceptions-nostd/src/panicking.rs
index 52a32f3cd30..414c9f6a165 100644
--- a/tests/run-make/wasm-exceptions-nostd/src/panicking.rs
+++ b/tests/run-make/wasm-exceptions-nostd/src/panicking.rs
@@ -17,8 +17,8 @@ fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
     use alloc::boxed::Box;
     use alloc::string::ToString;
 
-    let msg = info.message().map(|msg| msg.to_string()).unwrap_or("(no message)".to_string());
-    let exception = Box::new(msg.to_string());
+    let msg = info.message().to_string();
+    let exception = Box::new(msg);
     unsafe {
         let exception_raw = Box::into_raw(exception);
         wasm_throw(exception_raw as *mut u8);
diff --git a/tests/run-make/wasm-override-linker/Makefile b/tests/run-make/wasm-override-linker/Makefile
deleted file mode 100644
index 1a01a574dee..00000000000
--- a/tests/run-make/wasm-override-linker/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# needs-force-clang-based-tests
-
-# FIXME(#126180): This test doesn't actually run anywhere, because the only
-# CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests.
-
-include ../tools.mk
-
-ifeq ($(TARGET),wasm32-unknown-unknown)
-all:
-	$(RUSTC) foo.rs --crate-type cdylib --target $(TARGET) -C linker=$(CLANG)
-else ifeq ($(TARGET),wasm64-unknown-unknown)
-all:
-	$(RUSTC) foo.rs --crate-type cdylib --target $(TARGET) -C linker=$(CLANG)
-else
-all:
-endif
diff --git a/tests/run-make/wasm-override-linker/rmake.rs b/tests/run-make/wasm-override-linker/rmake.rs
new file mode 100644
index 00000000000..01bc08e9901
--- /dev/null
+++ b/tests/run-make/wasm-override-linker/rmake.rs
@@ -0,0 +1,17 @@
+// How to run this
+// $ RUSTBUILD_FORCE_CLANG_BASED_TESTS=1 ./x.py test tests/run-make/wasm-override-linker/
+
+//@ needs-force-clang-based-tests
+
+use run_make_support::{env_var, rustc, target};
+
+fn main() {
+    if matches!(target().as_str(), "wasm32-unknown-unknown" | "wasm64-unknown-unknown") {
+        rustc()
+            .input("foo.rs")
+            .crate_type("cdylib")
+            .target(&target())
+            .linker(&env_var("CLANG"))
+            .run();
+    }
+}
diff --git a/tests/run-make/weird-output-filenames/Makefile b/tests/run-make/weird-output-filenames/Makefile
deleted file mode 100644
index d3a34e3b46e..00000000000
--- a/tests/run-make/weird-output-filenames/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-include ../tools.mk
-
-all:
-	cp foo.rs $(TMPDIR)/.foo.rs
-	$(RUSTC) $(TMPDIR)/.foo.rs 2>&1 \
-		| $(CGREP) -e "invalid character.*in crate name:"
-	cp foo.rs $(TMPDIR)/.foo.bar
-	$(RUSTC) $(TMPDIR)/.foo.bar 2>&1 \
-		| $(CGREP) -e "invalid character.*in crate name:"
-	cp foo.rs $(TMPDIR)/+foo+bar.rs
-	$(RUSTC) $(TMPDIR)/+foo+bar.rs 2>&1 \
-		| $(CGREP) -e "invalid character.*in crate name:"
-	cp foo.rs $(TMPDIR)/-foo.rs
-	$(RUSTC) $(TMPDIR)/-foo.rs 2>&1 \
-		| $(CGREP) 'crate names cannot start with a `-`'
diff --git a/tests/run-make/weird-output-filenames/rmake.rs b/tests/run-make/weird-output-filenames/rmake.rs
new file mode 100644
index 00000000000..ed331a0b8d4
--- /dev/null
+++ b/tests/run-make/weird-output-filenames/rmake.rs
@@ -0,0 +1,19 @@
+use run_make_support::fs_wrapper::copy;
+use run_make_support::regex::Regex;
+use run_make_support::{cwd, rustc};
+
+fn main() {
+    let invalid_characters = [".foo.rs", ".foo.bar", "+foo+bar.rs"];
+    let re = Regex::new(r"invalid character.*in crate name:").unwrap();
+    for f in invalid_characters {
+        copy("foo.rs", f);
+        let stderr = rustc().input(f).run_fail().stderr_utf8();
+        assert!(re.is_match(&stderr));
+    }
+
+    copy("foo.rs", "-foo.rs");
+    rustc()
+        .input(cwd().join("-foo.rs"))
+        .run_fail()
+        .assert_stderr_contains("crate names cannot start with a `-`");
+}
diff --git a/tests/rustdoc-json/lifetime/outlives_in_param.rs b/tests/rustdoc-json/lifetime/outlives_in_param.rs
new file mode 100644
index 00000000000..f6db93c9183
--- /dev/null
+++ b/tests/rustdoc-json/lifetime/outlives_in_param.rs
@@ -0,0 +1,8 @@
+// ignore-tidy-linelength
+
+// @count '$.index[*][?(@.name=="outlives")].inner.function.generics.params[*]' 2
+// @is    '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].name' \"\'a\"
+// @is    '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].kind.lifetime.outlives' []
+// @is    '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].name' '"T"'
+// @is    '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].kind.type.bounds' '[{"outlives": "'\''a"}]'
+pub fn outlives<'a, T: 'a>() {}
diff --git a/tests/rustdoc-json/lifetime/outlives_in_where.rs b/tests/rustdoc-json/lifetime/outlives_in_where.rs
new file mode 100644
index 00000000000..ca3e1a150ce
--- /dev/null
+++ b/tests/rustdoc-json/lifetime/outlives_in_where.rs
@@ -0,0 +1,24 @@
+// ignore-tidy-linelength
+
+// @is '$.index[*][?(@.name=="on_lifetimes")].inner.function.generics.where_predicates' '[{"lifetime_predicate": {"lifetime": "'\''all", "outlives": ["'\''a", "'\''b", "'\''c"]}}]'
+pub fn on_lifetimes<'a, 'b, 'c, 'all>()
+where
+    'all: 'a + 'b + 'c,
+{
+}
+
+// @count '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[*]' 2
+// @is    '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].name' \"\'a\"
+// @is    '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].kind.lifetime.outlives' []
+// @is    '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].name' '"T"'
+// @is    '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' []
+// @is    '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' []
+// @count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[*]' 1
+// @is    '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.type.generic' '"T"'
+// @count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]' 1
+// @is    '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].outlives' \"\'a\"
+pub fn on_trait<'a, T>()
+where
+    T: 'a,
+{
+}
diff --git a/tests/rustdoc-json/trait_alias.rs b/tests/rustdoc-json/trait_alias.rs
new file mode 100644
index 00000000000..dc930550ef1
--- /dev/null
+++ b/tests/rustdoc-json/trait_alias.rs
@@ -0,0 +1,18 @@
+// ignore-tidy-linelength
+#![feature(trait_alias)]
+
+// @set StrLike = "$.index[*][?(@.name=='StrLike')].id"
+// @is "$.index[*][?(@.name=='StrLike')].visibility" \"public\"
+// @has "$.index[*][?(@.name=='StrLike')].inner.trait_alias"
+// @is "$.index[*][?(@.name=='StrLike')].span.filename" $FILE
+pub trait StrLike = AsRef<str>;
+
+// @is "$.index[*][?(@.name=='f')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $StrLike
+pub fn f() -> impl StrLike {
+    "heya"
+}
+
+// @!is "$.index[*][?(@.name=='g')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $StrLike
+pub fn g() -> impl AsRef<str> {
+    "heya"
+}
diff --git a/tests/rustdoc-json/type_alias.rs b/tests/rustdoc-json/type_alias.rs
new file mode 100644
index 00000000000..7a938c50ba0
--- /dev/null
+++ b/tests/rustdoc-json/type_alias.rs
@@ -0,0 +1,15 @@
+// @set IntVec = "$.index[*][?(@.name=='IntVec')].id"
+// @is "$.index[*][?(@.name=='IntVec')].visibility" \"public\"
+// @has "$.index[*][?(@.name=='IntVec')].inner.type_alias"
+// @is "$.index[*][?(@.name=='IntVec')].span.filename" $FILE
+pub type IntVec = Vec<u32>;
+
+// @is "$.index[*][?(@.name=='f')].inner.function.decl.output.resolved_path.id" $IntVec
+pub fn f() -> IntVec {
+    vec![0; 32]
+}
+
+// @!is "$.index[*][?(@.name=='g')].inner.function.decl.output.resolved_path.id" $IntVec
+pub fn g() -> Vec<u32> {
+    vec![0; 32]
+}
diff --git a/tests/rustdoc-ui/diagnostic-width.stderr b/tests/rustdoc-ui/diagnostic-width.stderr
index c1cc4898ac5..d8c4934a576 100644
--- a/tests/rustdoc-ui/diagnostic-width.stderr
+++ b/tests/rustdoc-ui/diagnostic-width.stderr
@@ -2,7 +2,7 @@ error: this URL is not a hyperlink
   --> $DIR/diagnostic-width.rs:4:41
    |
 LL | ... a http://link.com
-   |       ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://link.com>`
+   |       ^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
 note: the lint level is defined here
@@ -10,6 +10,10 @@ note: the lint level is defined here
    |
 LL | ...ny(rustdoc::bare_url...
    |       ^^^^^^^^^^^^^^^^^^
+help: use an automatic link instead
+   |
+LL | /// This is a long line that contains a <http://link.com>
+   |                                         +               +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/rustdoc-ui/include-str-bare-urls.stderr b/tests/rustdoc-ui/include-str-bare-urls.stderr
index a4234196b23..53da2411874 100644
--- a/tests/rustdoc-ui/include-str-bare-urls.stderr
+++ b/tests/rustdoc-ui/include-str-bare-urls.stderr
@@ -2,7 +2,7 @@ error: this URL is not a hyperlink
   --> $DIR/auxiliary/include-str-bare-urls.md:1:11
    |
 LL | HEADS UP! https://example.com MUST SHOW UP IN THE STDERR FILE!
-   |           ^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com>`
+   |           ^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
 note: the lint level is defined here
@@ -10,6 +10,10 @@ note: the lint level is defined here
    |
 LL | #![deny(rustdoc::bare_urls)]
    |         ^^^^^^^^^^^^^^^^^^
+help: use an automatic link instead
+   |
+LL | HEADS UP! <https://example.com> MUST SHOW UP IN THE STDERR FILE!
+   |           +                   +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/rustdoc-ui/lints/bare-urls.stderr b/tests/rustdoc-ui/lints/bare-urls.stderr
index ccf52cd0b93..ddfc387eaf6 100644
--- a/tests/rustdoc-ui/lints/bare-urls.stderr
+++ b/tests/rustdoc-ui/lints/bare-urls.stderr
@@ -2,7 +2,7 @@ error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:5:5
    |
 LL | /// https://somewhere.com
-   |     ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
+   |     ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
 note: the lint level is defined here
@@ -10,134 +10,202 @@ note: the lint level is defined here
    |
 LL | #![deny(rustdoc::bare_urls)]
    |         ^^^^^^^^^^^^^^^^^^
+help: use an automatic link instead
+   |
+LL | /// <https://somewhere.com>
+   |     +                     +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:7:5
    |
 LL | /// https://somewhere.com/a
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://somewhere.com/a>
+   |     +                       +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:9:5
    |
 LL | /// https://www.somewhere.com
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://www.somewhere.com>
+   |     +                         +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:11:5
    |
 LL | /// https://www.somewhere.com/a
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://www.somewhere.com/a>
+   |     +                           +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:13:5
    |
 LL | /// https://subdomain.example.com
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://subdomain.example.com>
+   |     +                             +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:15:5
    |
 LL | /// https://somewhere.com?
-   |     ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://somewhere.com?>
+   |     +                      +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:17:5
    |
 LL | /// https://somewhere.com/a?
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://somewhere.com/a?>
+   |     +                        +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:19:5
    |
 LL | /// https://somewhere.com?hello=12
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://somewhere.com?hello=12>
+   |     +                              +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:21:5
    |
 LL | /// https://somewhere.com/a?hello=12
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://somewhere.com/a?hello=12>
+   |     +                                +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:23:5
    |
 LL | /// https://example.com?hello=12#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://example.com?hello=12#xyz>
+   |     +                                +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:25:5
    |
 LL | /// https://example.com/a?hello=12#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://example.com/a?hello=12#xyz>
+   |     +                                  +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:27:5
    |
 LL | /// https://example.com#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://example.com#xyz>
+   |     +                       +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:29:5
    |
 LL | /// https://example.com/a#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://example.com/a#xyz>
+   |     +                         +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:31:5
    |
 LL | /// https://somewhere.com?hello=12&bye=11
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://somewhere.com?hello=12&bye=11>
+   |     +                                     +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:33:5
    |
 LL | /// https://somewhere.com/a?hello=12&bye=11
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://somewhere.com/a?hello=12&bye=11>
+   |     +                                       +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:35:5
    |
 LL | /// https://somewhere.com?hello=12&bye=11#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://somewhere.com?hello=12&bye=11#xyz>
+   |     +                                         +
 
 error: this URL is not a hyperlink
   --> $DIR/bare-urls.rs:37:10
    |
 LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// hey! <https://somewhere.com/a?hello=12&bye=11#xyz>
+   |          +                                           +
 
 error: aborting due to 17 previous errors
 
diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr
index ee9b67cb91b..88807dfb495 100644
--- a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr
+++ b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr
@@ -29,7 +29,7 @@ error: this URL is not a hyperlink
   --> $DIR/renamed-lint-still-applies.rs:9:5
    |
 LL | //! http://example.com
-   |     ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.com>`
+   |     ^^^^^^^^^^^^^^^^^^
    |
    = note: bare URLs are not automatically turned into clickable links
 note: the lint level is defined here
@@ -37,6 +37,10 @@ note: the lint level is defined here
    |
 LL | #![deny(rustdoc::non_autolinks)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
+help: use an automatic link instead
+   |
+LL | //! <http://example.com>
+   |     +                  +
 
 error: aborting due to 2 previous errors; 2 warnings emitted
 
diff --git a/tests/rustdoc-ui/unportable-markdown.rs b/tests/rustdoc-ui/unportable-markdown.rs
new file mode 100644
index 00000000000..8035e680f3c
--- /dev/null
+++ b/tests/rustdoc-ui/unportable-markdown.rs
@@ -0,0 +1,63 @@
+// https://internals.rust-lang.org/t/proposal-migrate-the-syntax-of-rustdoc-markdown-footnotes-to-be-compatible-with-the-syntax-used-in-github/18929
+//
+// A series of test cases for CommonMark corner cases that pulldown-cmark 0.11 fixes.
+//
+// This version of the lint is targeted at two especially-common cases where docs got broken.
+// Other differences in parsing should not warn.
+#![allow(rustdoc::broken_intra_doc_links)]
+#![deny(rustdoc::unportable_markdown)]
+
+/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/654>
+///
+/// Test footnote [^foot].
+///
+/// [^foot]: This is nested within the footnote now, but didn't used to be.
+///
+///     This is a multi-paragraph footnote.
+pub struct GfmFootnotes;
+
+/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/773>
+///
+/// test [^foo][^bar]
+//~^ ERROR unportable markdown
+///
+/// [^foo]: test
+/// [^bar]: test2
+pub struct FootnoteSmashedName;
+
+/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/829>
+///
+/// - _t
+///   # test
+///   t_
+pub struct NestingCornerCase;
+
+/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/650>
+///
+/// *~~__emphasis strike strong__~~* ~~*__strike emphasis strong__*~~
+pub struct Emphasis1;
+
+/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/732>
+///
+/// |
+/// |
+pub struct NotEnoughTable;
+
+/// <https://github.com/pulldown-cmark/pulldown-cmark/pull/675>
+///
+/// foo
+/// >bar
+//~^ ERROR unportable markdown
+pub struct BlockQuoteNoSpace;
+
+/// Negative test.
+///
+/// foo
+/// > bar
+pub struct BlockQuoteSpace;
+
+/// Negative test.
+///
+/// >bar
+/// baz
+pub struct BlockQuoteNoSpaceStart;
diff --git a/tests/rustdoc-ui/unportable-markdown.stderr b/tests/rustdoc-ui/unportable-markdown.stderr
new file mode 100644
index 00000000000..b524aca25ae
--- /dev/null
+++ b/tests/rustdoc-ui/unportable-markdown.stderr
@@ -0,0 +1,39 @@
+error: unportable markdown
+  --> $DIR/unportable-markdown.rs:21:10
+   |
+LL | /// test [^foo][^bar]
+   |          ^^^^^^
+   |
+   = help: confusing footnote reference and link
+note: the lint level is defined here
+  --> $DIR/unportable-markdown.rs:8:9
+   |
+LL | #![deny(rustdoc::unportable_markdown)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: if it should not be a footnote, escape it
+   |
+LL | /// test \[^foo][^bar]
+   |          +
+help: if the footnote is intended, add a space
+   |
+LL | /// test [^foo] [^bar]
+   |                +
+
+error: unportable markdown
+  --> $DIR/unportable-markdown.rs:49:5
+   |
+LL | /// >bar
+   |     ^
+   |
+   = help: confusing block quote with no space after the `>` marker
+help: if the quote is intended, add a space
+   |
+LL | /// > bar
+   |      +
+help: if it should not be a quote, escape it
+   |
+LL | /// \>bar
+   |     +
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui-fulldeps/deriving-global.rs b/tests/ui-fulldeps/deriving-global.rs
index 7783010be44..0ba149c9ad6 100644
--- a/tests/ui-fulldeps/deriving-global.rs
+++ b/tests/ui-fulldeps/deriving-global.rs
@@ -17,18 +17,21 @@ mod submod {
     // if any of these are implemented without global calls for any
     // function calls, then being in a submodule will (correctly)
     // cause errors about unrecognised module `std` (or `extra`)
+    #[allow(dead_code)]
     #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)]
     enum A {
         A1(usize),
         A2(isize),
     }
 
+    #[allow(dead_code)]
     #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)]
     struct B {
         x: usize,
         y: isize,
     }
 
+    #[allow(dead_code)]
     #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, Debug, Encodable, Decodable)]
     struct C(usize, isize);
 }
diff --git a/tests/ui-fulldeps/deriving-hygiene.rs b/tests/ui-fulldeps/deriving-hygiene.rs
index a3a6f9e022e..f948d6ac544 100644
--- a/tests/ui-fulldeps/deriving-hygiene.rs
+++ b/tests/ui-fulldeps/deriving-hygiene.rs
@@ -20,6 +20,7 @@ pub const s: u8 = 1;
 pub const state: u8 = 1;
 pub const cmp: u8 = 1;
 
+#[allow(dead_code)]
 #[derive(Ord, Eq, PartialOrd, PartialEq, Debug, Decodable, Encodable, Hash)]
 struct Foo {}
 
diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs
index 02748626723..720fc42cc57 100644
--- a/tests/ui-fulldeps/run-compiler-twice.rs
+++ b/tests/ui-fulldeps/run-compiler-twice.rs
@@ -17,6 +17,7 @@ extern crate rustc_span;
 
 use std::path::{Path, PathBuf};
 
+use rustc_interface::Linker;
 use rustc_interface::interface;
 use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes};
 use rustc_span::FileName;
@@ -78,8 +79,10 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path
 
     interface::run_compiler(config, |compiler| {
         let linker = compiler.enter(|queries| {
-            queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
-            queries.codegen_and_build_linker()
+            queries.global_ctxt()?.enter(|tcx| {
+                tcx.analysis(())?;
+                Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)
+            })
         });
         linker.unwrap().link(&compiler.sess, &*compiler.codegen_backend).unwrap();
     });
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
index 1be9ada2822..ca78604edd8 100644
--- a/tests/ui/abi/compatibility.rs
+++ b/tests/ui/abi/compatibility.rs
@@ -271,6 +271,11 @@ test_abi_compatible!(zst_unit, Zst, ());
 test_abi_compatible!(zst_array, Zst, [u8; 0]);
 test_abi_compatible!(nonzero_int, NonZero<i32>, i32);
 
+// `#[repr(C)]` enums should not change ABI based on individual variant inhabitedness.
+// (However, this is *not* a guarantee. We only guarantee same layout, not same ABI.)
+enum Void {}
+test_abi_compatible!(repr_c_enum_void, ReprCEnum<Void>, ReprCEnum<ReprCUnion<Void>>);
+
 // `DispatchFromDyn` relies on ABI compatibility.
 // This is interesting since these types are not `repr(transparent)`. So this is not part of our
 // public ABI guarantees, but is relied on by the compiler.
diff --git a/tests/ui/argument-suggestions/basic.stderr b/tests/ui/argument-suggestions/basic.stderr
index c74186285f9..ea58ca97cfa 100644
--- a/tests/ui/argument-suggestions/basic.stderr
+++ b/tests/ui/argument-suggestions/basic.stderr
@@ -16,16 +16,18 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/basic.rs:21:5
    |
 LL |     extra("");
-   |     ^^^^^ --
-   |           |
-   |           unexpected argument of type `&'static str`
-   |           help: remove the extra argument
+   |     ^^^^^ -- unexpected argument of type `&'static str`
    |
 note: function defined here
   --> $DIR/basic.rs:14:4
    |
 LL | fn extra() {}
    |    ^^^^^
+help: remove the extra argument
+   |
+LL -     extra("");
+LL +     extra();
+   |
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/basic.rs:22:5
diff --git a/tests/ui/argument-suggestions/exotic-calls.stderr b/tests/ui/argument-suggestions/exotic-calls.stderr
index ff795b507f2..aca3b8a3433 100644
--- a/tests/ui/argument-suggestions/exotic-calls.stderr
+++ b/tests/ui/argument-suggestions/exotic-calls.stderr
@@ -2,61 +2,69 @@ error[E0057]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/exotic-calls.rs:2:5
    |
 LL |     t(1i32);
-   |     ^ ----
-   |       |
-   |       unexpected argument of type `i32`
-   |       help: remove the extra argument
+   |     ^ ---- unexpected argument of type `i32`
    |
 note: callable defined here
   --> $DIR/exotic-calls.rs:1:11
    |
 LL | fn foo<T: Fn()>(t: T) {
    |           ^^^^
+help: remove the extra argument
+   |
+LL -     t(1i32);
+LL +     t();
+   |
 
 error[E0057]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/exotic-calls.rs:7:5
    |
 LL |     t(1i32);
-   |     ^ ----
-   |       |
-   |       unexpected argument of type `i32`
-   |       help: remove the extra argument
+   |     ^ ---- unexpected argument of type `i32`
    |
 note: type parameter defined here
   --> $DIR/exotic-calls.rs:6:11
    |
 LL | fn bar(t: impl Fn()) {
    |           ^^^^^^^^^
+help: remove the extra argument
+   |
+LL -     t(1i32);
+LL +     t();
+   |
 
 error[E0057]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/exotic-calls.rs:16:5
    |
 LL |     baz()(1i32)
-   |     ^^^^^ ----
-   |           |
-   |           unexpected argument of type `i32`
-   |           help: remove the extra argument
+   |     ^^^^^ ---- unexpected argument of type `i32`
    |
 note: opaque type defined here
   --> $DIR/exotic-calls.rs:11:13
    |
 LL | fn baz() -> impl Fn() {
    |             ^^^^^^^^^
+help: remove the extra argument
+   |
+LL -     baz()(1i32)
+LL +     baz()()
+   |
 
 error[E0057]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/exotic-calls.rs:22:5
    |
 LL |     x(1i32);
-   |     ^ ----
-   |       |
-   |       unexpected argument of type `i32`
-   |       help: remove the extra argument
+   |     ^ ---- unexpected argument of type `i32`
    |
 note: closure defined here
   --> $DIR/exotic-calls.rs:21:13
    |
 LL |     let x = || {};
    |             ^^
+help: remove the extra argument
+   |
+LL -     x(1i32);
+LL +     x();
+   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr
index 5ad8e35920a..dec3da75186 100644
--- a/tests/ui/argument-suggestions/extra_arguments.stderr
+++ b/tests/ui/argument-suggestions/extra_arguments.stderr
@@ -2,16 +2,18 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/extra_arguments.rs:19:3
    |
 LL |   empty("");
-   |   ^^^^^ --
-   |         |
-   |         unexpected argument of type `&'static str`
-   |         help: remove the extra argument
+   |   ^^^^^ -- unexpected argument of type `&'static str`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:1:4
    |
 LL | fn empty() {}
    |    ^^^^^
+help: remove the extra argument
+   |
+LL -   empty("");
+LL +   empty();
+   |
 
 error[E0061]: this function takes 0 arguments but 2 arguments were supplied
   --> $DIR/extra_arguments.rs:20:3
@@ -36,31 +38,35 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/extra_arguments.rs:22:3
    |
 LL |   one_arg(1, 1);
-   |   ^^^^^^^  ---
-   |            | |
-   |            | unexpected argument of type `{integer}`
-   |            help: remove the extra argument
+   |   ^^^^^^^    - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:2:4
    |
 LL | fn one_arg<T>(_a: T) {}
    |    ^^^^^^^    -----
+help: remove the extra argument
+   |
+LL -   one_arg(1, 1);
+LL +   one_arg(1);
+   |
 
 error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/extra_arguments.rs:23:3
    |
 LL |   one_arg(1, "");
-   |   ^^^^^^^  ----
-   |            | |
-   |            | unexpected argument of type `&'static str`
-   |            help: remove the extra argument
+   |   ^^^^^^^    -- unexpected argument of type `&'static str`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:2:4
    |
 LL | fn one_arg<T>(_a: T) {}
    |    ^^^^^^^    -----
+help: remove the extra argument
+   |
+LL -   one_arg(1, "");
+LL +   one_arg(1);
+   |
 
 error[E0061]: this function takes 1 argument but 3 arguments were supplied
   --> $DIR/extra_arguments.rs:24:3
@@ -85,61 +91,69 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/extra_arguments.rs:26:3
    |
 LL |   two_arg_same(1, 1, 1);
-   |   ^^^^^^^^^^^^     ---
-   |                    | |
-   |                    | unexpected argument of type `{integer}`
-   |                    help: remove the extra argument
+   |   ^^^^^^^^^^^^       - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:3:4
    |
 LL | fn two_arg_same(_a: i32, _b: i32) {}
    |    ^^^^^^^^^^^^ -------  -------
+help: remove the extra argument
+   |
+LL -   two_arg_same(1, 1, 1);
+LL +   two_arg_same(1, 1);
+   |
 
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/extra_arguments.rs:27:3
    |
 LL |   two_arg_same(1, 1, 1.0);
-   |   ^^^^^^^^^^^^     -----
-   |                    | |
-   |                    | unexpected argument of type `{float}`
-   |                    help: remove the extra argument
+   |   ^^^^^^^^^^^^       --- unexpected argument of type `{float}`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:3:4
    |
 LL | fn two_arg_same(_a: i32, _b: i32) {}
    |    ^^^^^^^^^^^^ -------  -------
+help: remove the extra argument
+   |
+LL -   two_arg_same(1, 1, 1.0);
+LL +   two_arg_same(1, 1);
+   |
 
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/extra_arguments.rs:29:3
    |
 LL |   two_arg_diff(1, 1, "");
-   |   ^^^^^^^^^^^^  ---
-   |                 | |
-   |                 | unexpected argument of type `{integer}`
-   |                 help: remove the extra argument
+   |   ^^^^^^^^^^^^    - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:4:4
    |
 LL | fn two_arg_diff(_a: i32, _b: &str) {}
    |    ^^^^^^^^^^^^ -------  --------
+help: remove the extra argument
+   |
+LL -   two_arg_diff(1, 1, "");
+LL +   two_arg_diff(1, "");
+   |
 
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/extra_arguments.rs:30:3
    |
 LL |   two_arg_diff(1, "", "");
-   |   ^^^^^^^^^^^^      ----
-   |                     | |
-   |                     | unexpected argument of type `&'static str`
-   |                     help: remove the extra argument
+   |   ^^^^^^^^^^^^        -- unexpected argument of type `&'static str`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:4:4
    |
 LL | fn two_arg_diff(_a: i32, _b: &str) {}
    |    ^^^^^^^^^^^^ -------  --------
+help: remove the extra argument
+   |
+LL -   two_arg_diff(1, "", "");
+LL +   two_arg_diff(1, "");
+   |
 
 error[E0061]: this function takes 2 arguments but 4 arguments were supplied
   --> $DIR/extra_arguments.rs:31:3
@@ -183,70 +197,75 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/extra_arguments.rs:35:3
    |
 LL |   two_arg_same(1, 1,     "");
-   |   ^^^^^^^^^^^^     --------
-   |                    |     |
-   |                    |     unexpected argument of type `&'static str`
-   |                    help: remove the extra argument
+   |   ^^^^^^^^^^^^           -- unexpected argument of type `&'static str`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:3:4
    |
 LL | fn two_arg_same(_a: i32, _b: i32) {}
    |    ^^^^^^^^^^^^ -------  -------
+help: remove the extra argument
+   |
+LL -   two_arg_same(1, 1,     "");
+LL +   two_arg_same(1, 1);
+   |
 
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/extra_arguments.rs:36:3
    |
 LL |   two_arg_diff(1, 1,     "");
-   |   ^^^^^^^^^^^^  ---
-   |                 | |
-   |                 | unexpected argument of type `{integer}`
-   |                 help: remove the extra argument
+   |   ^^^^^^^^^^^^    - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:4:4
    |
 LL | fn two_arg_diff(_a: i32, _b: &str) {}
    |    ^^^^^^^^^^^^ -------  --------
+help: remove the extra argument
+   |
+LL -   two_arg_diff(1, 1,     "");
+LL +   two_arg_diff(1,     "");
+   |
 
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/extra_arguments.rs:37:3
    |
-LL |     two_arg_same(
-   |     ^^^^^^^^^^^^
-LL |       1,
-LL |       1,
-   |  ______-
-LL | |     ""
-   | |     --
-   | |_____||
-   |       |help: remove the extra argument
-   |       unexpected argument of type `&'static str`
+LL |   two_arg_same(
+   |   ^^^^^^^^^^^^
+...
+LL |     ""
+   |     -- unexpected argument of type `&'static str`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:3:4
    |
 LL | fn two_arg_same(_a: i32, _b: i32) {}
    |    ^^^^^^^^^^^^ -------  -------
+help: remove the extra argument
+   |
+LL -     1,
+LL -     ""
+LL +     1
+   |
 
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/extra_arguments.rs:43:3
    |
-LL |     two_arg_diff(
-   |     ^^^^^^^^^^^^
-LL |       1,
-   |  ______-
-LL | |     1,
-   | |     -
-   | |     |
-   | |_____unexpected argument of type `{integer}`
-   |       help: remove the extra argument
+LL |   two_arg_diff(
+   |   ^^^^^^^^^^^^
+LL |     1,
+LL |     1,
+   |     - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:4:4
    |
 LL | fn two_arg_diff(_a: i32, _b: &str) {}
    |    ^^^^^^^^^^^^ -------  --------
+help: remove the extra argument
+   |
+LL -     1,
+   |
 
 error[E0061]: this function takes 0 arguments but 2 arguments were supplied
   --> $DIR/extra_arguments.rs:8:9
@@ -310,61 +329,69 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/extra_arguments.rs:53:3
    |
 LL |   one_arg(1, panic!());
-   |   ^^^^^^^  ----------
-   |            | |
-   |            | unexpected argument
-   |            help: remove the extra argument
+   |   ^^^^^^^    -------- unexpected argument
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:2:4
    |
 LL | fn one_arg<T>(_a: T) {}
    |    ^^^^^^^    -----
+help: remove the extra argument
+   |
+LL -   one_arg(1, panic!());
+LL +   one_arg(1);
+   |
 
 error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/extra_arguments.rs:54:3
    |
 LL |   one_arg(panic!(), 1);
-   |   ^^^^^^^         ---
-   |                   | |
-   |                   | unexpected argument of type `{integer}`
-   |                   help: remove the extra argument
+   |   ^^^^^^^           - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:2:4
    |
 LL | fn one_arg<T>(_a: T) {}
    |    ^^^^^^^    -----
+help: remove the extra argument
+   |
+LL -   one_arg(panic!(), 1);
+LL +   one_arg(panic!());
+   |
 
 error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/extra_arguments.rs:55:3
    |
 LL |   one_arg(stringify!($e), 1);
-   |   ^^^^^^^               ---
-   |                         | |
-   |                         | unexpected argument of type `{integer}`
-   |                         help: remove the extra argument
+   |   ^^^^^^^                 - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:2:4
    |
 LL | fn one_arg<T>(_a: T) {}
    |    ^^^^^^^    -----
+help: remove the extra argument
+   |
+LL -   one_arg(stringify!($e), 1);
+LL +   one_arg(stringify!($e));
+   |
 
 error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/extra_arguments.rs:60:3
    |
 LL |   one_arg(for _ in 1.. {}, 1);
-   |   ^^^^^^^                ---
-   |                          | |
-   |                          | unexpected argument of type `{integer}`
-   |                          help: remove the extra argument
+   |   ^^^^^^^                  - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/extra_arguments.rs:2:4
    |
 LL | fn one_arg<T>(_a: T) {}
    |    ^^^^^^^    -----
+help: remove the extra argument
+   |
+LL -   one_arg(for _ in 1.. {}, 1);
+LL +   one_arg(for _ in 1.. {});
+   |
 
 error: aborting due to 22 previous errors
 
diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs
new file mode 100644
index 00000000000..fa1802283c3
--- /dev/null
+++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs
@@ -0,0 +1,21 @@
+fn add_one(x: i32) -> i32 {
+    x + 1
+}
+
+fn add_two(x: i32, y: i32) -> i32 {
+    x + y
+}
+
+fn main() {
+    add_one(2, 2); //~ ERROR this function takes 1 argument but 2 arguments were supplied
+    add_one(no_such_local, 10); //~ ERROR cannot find value `no_such_local` in this scope
+    //~| ERROR this function takes 1 argument but 2 arguments were supplied
+    add_one(10, no_such_local); //~ ERROR cannot find value `no_such_local` in this scope
+    //~| ERROR this function takes 1 argument but 2 arguments were supplied
+    add_two(10, no_such_local, 10); //~ ERROR cannot find value `no_such_local` in this scope
+    //~| ERROR this function takes 2 arguments but 3 arguments were supplied
+    add_two(no_such_local, 10, 10); //~ ERROR cannot find value `no_such_local` in this scope
+    //~| ERROR this function takes 2 arguments but 3 arguments were supplied
+    add_two(10, 10, no_such_local); //~ ERROR cannot find value `no_such_local` in this scope
+    //~| ERROR this function takes 2 arguments but 3 arguments were supplied
+}
diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr
new file mode 100644
index 00000000000..dc293945eb6
--- /dev/null
+++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr
@@ -0,0 +1,136 @@
+error[E0425]: cannot find value `no_such_local` in this scope
+  --> $DIR/suggest-better-removing-issue-126246.rs:11:13
+   |
+LL |     add_one(no_such_local, 10);
+   |             ^^^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `no_such_local` in this scope
+  --> $DIR/suggest-better-removing-issue-126246.rs:13:17
+   |
+LL |     add_one(10, no_such_local);
+   |                 ^^^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `no_such_local` in this scope
+  --> $DIR/suggest-better-removing-issue-126246.rs:15:17
+   |
+LL |     add_two(10, no_such_local, 10);
+   |                 ^^^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `no_such_local` in this scope
+  --> $DIR/suggest-better-removing-issue-126246.rs:17:13
+   |
+LL |     add_two(no_such_local, 10, 10);
+   |             ^^^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `no_such_local` in this scope
+  --> $DIR/suggest-better-removing-issue-126246.rs:19:21
+   |
+LL |     add_two(10, 10, no_such_local);
+   |                     ^^^^^^^^^^^^^ not found in this scope
+
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+  --> $DIR/suggest-better-removing-issue-126246.rs:10:5
+   |
+LL |     add_one(2, 2);
+   |     ^^^^^^^    - unexpected argument of type `{integer}`
+   |
+note: function defined here
+  --> $DIR/suggest-better-removing-issue-126246.rs:1:4
+   |
+LL | fn add_one(x: i32) -> i32 {
+   |    ^^^^^^^ ------
+help: remove the extra argument
+   |
+LL -     add_one(2, 2);
+LL +     add_one(2);
+   |
+
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+  --> $DIR/suggest-better-removing-issue-126246.rs:11:5
+   |
+LL |     add_one(no_such_local, 10);
+   |     ^^^^^^^ ------------- unexpected argument
+   |
+note: function defined here
+  --> $DIR/suggest-better-removing-issue-126246.rs:1:4
+   |
+LL | fn add_one(x: i32) -> i32 {
+   |    ^^^^^^^ ------
+help: remove the extra argument
+   |
+LL -     add_one(no_such_local, 10);
+LL +     add_one(10);
+   |
+
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+  --> $DIR/suggest-better-removing-issue-126246.rs:13:5
+   |
+LL |     add_one(10, no_such_local);
+   |     ^^^^^^^     ------------- unexpected argument
+   |
+note: function defined here
+  --> $DIR/suggest-better-removing-issue-126246.rs:1:4
+   |
+LL | fn add_one(x: i32) -> i32 {
+   |    ^^^^^^^ ------
+help: remove the extra argument
+   |
+LL -     add_one(10, no_such_local);
+LL +     add_one(10);
+   |
+
+error[E0061]: this function takes 2 arguments but 3 arguments were supplied
+  --> $DIR/suggest-better-removing-issue-126246.rs:15:5
+   |
+LL |     add_two(10, no_such_local, 10);
+   |     ^^^^^^^     ------------- unexpected argument
+   |
+note: function defined here
+  --> $DIR/suggest-better-removing-issue-126246.rs:5:4
+   |
+LL | fn add_two(x: i32, y: i32) -> i32 {
+   |    ^^^^^^^ ------  ------
+help: remove the extra argument
+   |
+LL -     add_two(10, no_such_local, 10);
+LL +     add_two(10, 10);
+   |
+
+error[E0061]: this function takes 2 arguments but 3 arguments were supplied
+  --> $DIR/suggest-better-removing-issue-126246.rs:17:5
+   |
+LL |     add_two(no_such_local, 10, 10);
+   |     ^^^^^^^ ------------- unexpected argument
+   |
+note: function defined here
+  --> $DIR/suggest-better-removing-issue-126246.rs:5:4
+   |
+LL | fn add_two(x: i32, y: i32) -> i32 {
+   |    ^^^^^^^ ------  ------
+help: remove the extra argument
+   |
+LL -     add_two(no_such_local, 10, 10);
+LL +     add_two(10, 10);
+   |
+
+error[E0061]: this function takes 2 arguments but 3 arguments were supplied
+  --> $DIR/suggest-better-removing-issue-126246.rs:19:5
+   |
+LL |     add_two(10, 10, no_such_local);
+   |     ^^^^^^^         ------------- unexpected argument
+   |
+note: function defined here
+  --> $DIR/suggest-better-removing-issue-126246.rs:5:4
+   |
+LL | fn add_two(x: i32, y: i32) -> i32 {
+   |    ^^^^^^^ ------  ------
+help: remove the extra argument
+   |
+LL -     add_two(10, 10, no_such_local);
+LL +     add_two(10, 10);
+   |
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0061, E0425.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/assign-imm-local-twice.rs b/tests/ui/assign-imm-local-twice.rs
index b50f6ab5deb..b2dfeb564d9 100644
--- a/tests/ui/assign-imm-local-twice.rs
+++ b/tests/ui/assign-imm-local-twice.rs
@@ -1,7 +1,7 @@
 fn test() {
     let v: isize;
     //~^ HELP consider making this binding mutable
-    //~| SUGGESTION mut v
+    //~| SUGGESTION mut
     v = 1; //~ NOTE first assignment
     println!("v={}", v);
     v = 2; //~ ERROR cannot assign twice to immutable variable
diff --git a/tests/ui/assign-imm-local-twice.stderr b/tests/ui/assign-imm-local-twice.stderr
index d92485de68f..fda3aa3de1b 100644
--- a/tests/ui/assign-imm-local-twice.stderr
+++ b/tests/ui/assign-imm-local-twice.stderr
@@ -1,14 +1,16 @@
 error[E0384]: cannot assign twice to immutable variable `v`
   --> $DIR/assign-imm-local-twice.rs:7:5
    |
-LL |     let v: isize;
-   |         - help: consider making this binding mutable: `mut v`
-...
 LL |     v = 1;
    |     ----- first assignment to `v`
 LL |     println!("v={}", v);
 LL |     v = 2;
    |     ^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut v: isize;
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs
index c23eff79ce2..a8c8a85c5aa 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs
+++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs
@@ -13,7 +13,7 @@ fn foo<T: Trait<method(i32): Send>>() {}
 fn bar<T: Trait<method() -> (): Send>>() {}
 //~^ ERROR return type not allowed with return type notation
 
-fn baz<T: Trait<method(..): Send>>() {}
-//~^ ERROR return type notation uses `()` instead of `(..)` for elided arguments
+fn baz<T: Trait<method(): Send>>() {}
+//~^ ERROR return type notation arguments must be elided with `..`
 
 fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr
index d95249efe40..7e1695984f1 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr
@@ -1,9 +1,3 @@
-error: return type notation uses `()` instead of `(..)` for elided arguments
-  --> $DIR/bad-inputs-and-output.rs:16:24
-   |
-LL | fn baz<T: Trait<method(..): Send>>() {}
-   |                        ^^ help: remove the `..`
-
 warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/bad-inputs-and-output.rs:3:12
    |
@@ -25,5 +19,11 @@ error: return type not allowed with return type notation
 LL | fn bar<T: Trait<method() -> (): Send>>() {}
    |                         ^^^^^^ help: remove the return type
 
+error: return type notation arguments must be elided with `..`
+  --> $DIR/bad-inputs-and-output.rs:16:23
+   |
+LL | fn baz<T: Trait<method(): Send>>() {}
+   |                       ^^ help: add `..`: `(..)`
+
 error: aborting due to 3 previous errors; 1 warning emitted
 
diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs
new file mode 100644
index 00000000000..f507d82afec
--- /dev/null
+++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs
@@ -0,0 +1,26 @@
+#![feature(return_type_notation)]
+//~^ WARN the feature `return_type_notation` is incomplete
+
+trait Tr {
+    const CONST: usize;
+
+    fn method() -> impl Sized;
+}
+
+fn foo<T: Tr>()
+where
+    T::method(..): Send,
+    //~^ ERROR return type notation not allowed in this position yet
+    //~| ERROR expected type, found function
+    <T as Tr>::method(..): Send,
+    //~^ ERROR return type notation not allowed in this position yet
+    //~| ERROR expected associated type, found associated function `Tr::method`
+{
+    let _ = T::CONST::(..);
+    //~^ ERROR return type notation not allowed in this position yet
+    let _: T::method(..);
+    //~^ ERROR return type notation not allowed in this position yet
+    //~| ERROR expected type, found function
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr
new file mode 100644
index 00000000000..cb45de59c7e
--- /dev/null
+++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr
@@ -0,0 +1,66 @@
+error[E0575]: expected associated type, found associated function `Tr::method`
+  --> $DIR/bare-path.rs:15:5
+   |
+LL |     <T as Tr>::method(..): Send,
+   |     ^^^^^^^^^^^^^^^^^^^^^ not a associated type
+
+warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/bare-path.rs:1:12
+   |
+LL | #![feature(return_type_notation)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: return type notation not allowed in this position yet
+  --> $DIR/bare-path.rs:19:23
+   |
+LL |     let _ = T::CONST::(..);
+   |                       ^^^^
+
+error: return type notation not allowed in this position yet
+  --> $DIR/bare-path.rs:21:21
+   |
+LL |     let _: T::method(..);
+   |                     ^^^^
+
+error: return type notation not allowed in this position yet
+  --> $DIR/bare-path.rs:12:14
+   |
+LL |     T::method(..): Send,
+   |              ^^^^
+
+error: return type notation not allowed in this position yet
+  --> $DIR/bare-path.rs:15:22
+   |
+LL |     <T as Tr>::method(..): Send,
+   |                      ^^^^
+
+error: expected type, found function
+  --> $DIR/bare-path.rs:12:8
+   |
+LL |     T::method(..): Send,
+   |        ^^^^^^ unexpected function
+   |
+note: the associated function is defined here
+  --> $DIR/bare-path.rs:7:5
+   |
+LL |     fn method() -> impl Sized;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected type, found function
+  --> $DIR/bare-path.rs:21:15
+   |
+LL |     let _: T::method(..);
+   |               ^^^^^^ unexpected function
+   |
+note: the associated function is defined here
+  --> $DIR/bare-path.rs:7:5
+   |
+LL |     fn method() -> impl Sized;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0575`.
diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.rs b/tests/ui/associated-type-bounds/return-type-notation/basic.rs
index 9755fd01c97..be489a19a7a 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/basic.rs
+++ b/tests/ui/associated-type-bounds/return-type-notation/basic.rs
@@ -17,7 +17,7 @@ async fn foo<T: Foo>() -> Result<(), ()> {
 fn is_send(_: impl Send) {}
 
 fn test<
-    #[cfg(with)] T: Foo<method(): Send>,
+    #[cfg(with)] T: Foo<method(..): Send>,
     #[cfg(without)] T: Foo,
 >() {
     is_send(foo::<T>());
diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.rs b/tests/ui/associated-type-bounds/return-type-notation/equality.rs
index ae38dce1818..95c16fa1e3f 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/equality.rs
+++ b/tests/ui/associated-type-bounds/return-type-notation/equality.rs
@@ -9,7 +9,7 @@ trait Trait {
     async fn method() {}
 }
 
-fn test<T: Trait<method() = Box<dyn Future<Output = ()>>>>() {}
+fn test<T: Trait<method(..) = Box<dyn Future<Output = ()>>>>() {}
 //~^ ERROR return type notation is not allowed to use type equality
 
 fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr
index d432e957735..d76b1bd1c05 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr
@@ -10,8 +10,8 @@ LL | #![feature(return_type_notation)]
 error: return type notation is not allowed to use type equality
   --> $DIR/equality.rs:12:18
    |
-LL | fn test<T: Trait<method() = Box<dyn Future<Output = ()>>>>() {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn test<T: Trait<method(..) = Box<dyn Future<Output = ()>>>>() {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs
index 11728b87990..4d026b7d1d8 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs
+++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs
@@ -9,7 +9,7 @@ trait HealthCheck {
 
 async fn do_health_check_par<HC>(hc: HC)
 where
-    HC: HealthCheck<check(): Send> + Send + 'static,
+    HC: HealthCheck<check(..): Send> + Send + 'static,
     //~^ ERROR return type notation is not allowed for functions that have const parameters
 {
 }
diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr
index 8a3f037d003..12f32a75eda 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr
@@ -13,8 +13,8 @@ error: return type notation is not allowed for functions that have const paramet
 LL |     async fn check<const N: usize>() -> bool;
    |                    -------------- const parameter declared here
 ...
-LL |     HC: HealthCheck<check(): Send> + Send + 'static,
-   |                     ^^^^^^^^^^^^^
+LL |     HC: HealthCheck<check(..): Send> + Send + 'static,
+   |                     ^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.rs b/tests/ui/associated-type-bounds/return-type-notation/missing.rs
index 9a8b77d00b7..3a04a56339b 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/missing.rs
+++ b/tests/ui/associated-type-bounds/return-type-notation/missing.rs
@@ -7,7 +7,7 @@ trait Trait {
     async fn method() {}
 }
 
-fn bar<T: Trait<methid(): Send>>() {}
+fn bar<T: Trait<methid(..): Send>>() {}
 //~^ ERROR associated function `methid` not found for `Trait`
 
 fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr
index db9cb9f49a3..5cb8e2642f5 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr
@@ -10,7 +10,7 @@ LL | #![feature(return_type_notation)]
 error[E0220]: associated function `methid` not found for `Trait`
   --> $DIR/missing.rs:10:17
    |
-LL | fn bar<T: Trait<methid(): Send>>() {}
+LL | fn bar<T: Trait<methid(..): Send>>() {}
    |                 ^^^^^^ help: there is an associated function with a similar name: `method`
 
 error: aborting due to 1 previous error; 1 warning emitted
diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs
index db5f6fe389e..d283c6eab37 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs
+++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs
@@ -5,7 +5,7 @@ trait Trait {
     fn method() {}
 }
 
-fn test<T: Trait<method(): Send>>() {}
+fn test<T: Trait<method(..): Send>>() {}
 //~^ ERROR  return type notation used on function that is not `async` and does not return `impl Trait`
 
 fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr
index 3e307c5f42c..79ced3c96ed 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr
@@ -13,8 +13,8 @@ error: return type notation used on function that is not `async` and does not re
 LL |     fn method() {}
    |     ----------- this function must be `async` or return `impl Trait`
 ...
-LL | fn test<T: Trait<method(): Send>>() {}
-   |                  ^^^^^^^^^^^^^^
+LL | fn test<T: Trait<method(..): Send>>() {}
+   |                  ^^^^^^^^^^^^^^^^
    |
    = note: function returns `()`, which is not compatible with associated type return bounds
 
diff --git a/tests/ui/associated-types/associated-types-eq-expr-path.rs b/tests/ui/associated-types/associated-types-eq-expr-path.rs
index 67831f91303..3179811274e 100644
--- a/tests/ui/associated-types/associated-types-eq-expr-path.rs
+++ b/tests/ui/associated-types/associated-types-eq-expr-path.rs
@@ -7,11 +7,12 @@ trait Foo {
 
 impl Foo for isize {
     type A = usize;
-    fn bar() -> isize { 42 }
+    fn bar() -> isize {
+        42
+    }
 }
 
 pub fn main() {
     let x: isize = Foo::<A = usize>::bar();
     //~^ ERROR associated item constraints are not allowed here
-    //~| ERROR cannot call
 }
diff --git a/tests/ui/associated-types/associated-types-eq-expr-path.stderr b/tests/ui/associated-types/associated-types-eq-expr-path.stderr
index 4f28b3cb2de..bbe021fbc55 100644
--- a/tests/ui/associated-types/associated-types-eq-expr-path.stderr
+++ b/tests/ui/associated-types/associated-types-eq-expr-path.stderr
@@ -1,25 +1,9 @@
 error[E0229]: associated item constraints are not allowed here
-  --> $DIR/associated-types-eq-expr-path.rs:14:26
+  --> $DIR/associated-types-eq-expr-path.rs:16:26
    |
 LL |     let x: isize = Foo::<A = usize>::bar();
    |                          ^^^^^^^^^ associated item constraint not allowed here
 
-error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
-  --> $DIR/associated-types-eq-expr-path.rs:14:20
-   |
-LL |     fn bar() -> isize;
-   |     ------------------ `Foo::bar` defined here
-...
-LL |     let x: isize = Foo::<A = usize>::bar();
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
-   |
-help: use the fully-qualified path to the only available implementation
-   |
-LL -     let x: isize = Foo::<A = usize>::bar();
-LL +     let x: isize = <isize as Foo<A = usize>>::bar();
-   |
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0229, E0790.
-For more information about an error, try `rustc --explain E0229`.
+For more information about this error, try `rustc --explain E0229`.
diff --git a/tests/ui/associated-types/defaults-specialization.stderr b/tests/ui/associated-types/defaults-specialization.stderr
index 7ef433d859f..b4ed99f36f4 100644
--- a/tests/ui/associated-types/defaults-specialization.stderr
+++ b/tests/ui/associated-types/defaults-specialization.stderr
@@ -12,10 +12,7 @@ error[E0053]: method `make` has an incompatible type for trait
   --> $DIR/defaults-specialization.rs:19:18
    |
 LL |     fn make() -> u8 { 0 }
-   |                  ^^
-   |                  |
-   |                  expected associated type, found `u8`
-   |                  help: change the output type to match the trait: `<A<T> as Tr>::Ty`
+   |                  ^^ expected associated type, found `u8`
    |
 note: type in trait
   --> $DIR/defaults-specialization.rs:9:18
@@ -24,6 +21,10 @@ LL |     fn make() -> Self::Ty {
    |                  ^^^^^^^^
    = note: expected signature `fn() -> <A<T> as Tr>::Ty`
               found signature `fn() -> u8`
+help: change the output type to match the trait
+   |
+LL |     fn make() -> <A<T> as Tr>::Ty { 0 }
+   |                  ~~~~~~~~~~~~~~~~
 
 error[E0053]: method `make` has an incompatible type for trait
   --> $DIR/defaults-specialization.rs:35:18
@@ -32,10 +33,7 @@ LL |     default type Ty = bool;
    |     ----------------------- associated type is `default` and may be overridden
 LL |
 LL |     fn make() -> bool { true }
-   |                  ^^^^
-   |                  |
-   |                  expected associated type, found `bool`
-   |                  help: change the output type to match the trait: `<B<T> as Tr>::Ty`
+   |                  ^^^^ expected associated type, found `bool`
    |
 note: type in trait
   --> $DIR/defaults-specialization.rs:9:18
@@ -44,6 +42,10 @@ LL |     fn make() -> Self::Ty {
    |                  ^^^^^^^^
    = note: expected signature `fn() -> <B<T> as Tr>::Ty`
               found signature `fn() -> bool`
+help: change the output type to match the trait
+   |
+LL |     fn make() -> <B<T> as Tr>::Ty { true }
+   |                  ~~~~~~~~~~~~~~~~
 
 error[E0308]: mismatched types
   --> $DIR/defaults-specialization.rs:10:9
diff --git a/tests/ui/associated-types/issue-22560.stderr b/tests/ui/associated-types/issue-22560.stderr
index 46e6e3951a5..834040490f9 100644
--- a/tests/ui/associated-types/issue-22560.stderr
+++ b/tests/ui/associated-types/issue-22560.stderr
@@ -35,9 +35,13 @@ LL | trait Add<Rhs=Self> {
    | ------------------- type parameter `Rhs` must be specified for this
 ...
 LL | type Test = dyn Add + Sub;
-   |                 ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
+   |                 ^^^
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
+help: set the type parameter to the desired type
+   |
+LL | type Test = dyn Add<Rhs> + Sub;
+   |                    +++++
 
 error[E0393]: the type parameter `Rhs` must be explicitly specified
   --> $DIR/issue-22560.rs:9:23
@@ -46,9 +50,13 @@ LL | trait Sub<Rhs=Self> {
    | ------------------- type parameter `Rhs` must be specified for this
 ...
 LL | type Test = dyn Add + Sub;
-   |                       ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
+   |                       ^^^
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
+help: set the type parameter to the desired type
+   |
+LL | type Test = dyn Add + Sub<Rhs>;
+   |                          +++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs b/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs
index a43906d01e5..3b222d00bae 100644
--- a/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs
+++ b/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs
@@ -1,5 +1,5 @@
 //@ edition: 2021
-//@ check-pass
+//@ build-pass
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
diff --git a/tests/ui/async-await/async-closures/force-move-due-to-actually-fnonce.rs b/tests/ui/async-await/async-closures/force-move-due-to-actually-fnonce.rs
index ce49f55e3e3..7244a29673b 100644
--- a/tests/ui/async-await/async-closures/force-move-due-to-actually-fnonce.rs
+++ b/tests/ui/async-await/async-closures/force-move-due-to-actually-fnonce.rs
@@ -1,6 +1,6 @@
 //@ aux-build:block-on.rs
 //@ edition:2021
-//@ check-pass
+//@ build-pass
 
 #![feature(async_closure)]
 
diff --git a/tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs b/tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs
index 803c990ef93..7ce210a33c3 100644
--- a/tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs
+++ b/tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs
@@ -1,6 +1,6 @@
 //@ aux-build:block-on.rs
 //@ edition:2021
-//@ check-pass
+//@ build-pass
 
 #![feature(async_closure)]
 
diff --git a/tests/ui/async-await/async-closures/implements-fnmut.rs b/tests/ui/async-await/async-closures/implements-fnmut.rs
index 1ed326cd061..8e780ce9889 100644
--- a/tests/ui/async-await/async-closures/implements-fnmut.rs
+++ b/tests/ui/async-await/async-closures/implements-fnmut.rs
@@ -1,4 +1,4 @@
-//@ check-pass
+//@ build-pass
 //@ edition: 2021
 
 // Demonstrates that an async closure may implement `FnMut` (not just `async FnMut`!)
@@ -9,9 +9,13 @@
 
 #![feature(async_closure)]
 
-fn main() {}
+fn main() {
+    hello(&Ty);
+}
 
-fn needs_fn_mut<T>(x: impl FnMut() -> T) {}
+fn needs_fn_mut<T>(mut x: impl FnMut() -> T) {
+    x();
+}
 
 fn hello(x: &Ty) {
     needs_fn_mut(async || { x.hello(); });
diff --git a/tests/ui/async-await/async-closures/signature-deduction.rs b/tests/ui/async-await/async-closures/signature-deduction.rs
index 031dab10296..856f3963ee6 100644
--- a/tests/ui/async-await/async-closures/signature-deduction.rs
+++ b/tests/ui/async-await/async-closures/signature-deduction.rs
@@ -1,4 +1,4 @@
-//@ check-pass
+//@ build-pass
 //@ edition: 2021
 
 #![feature(async_closure)]
diff --git a/tests/ui/async-await/async-closures/signature-inference-from-two-part-bound.rs b/tests/ui/async-await/async-closures/signature-inference-from-two-part-bound.rs
new file mode 100644
index 00000000000..0e2d1ef1208
--- /dev/null
+++ b/tests/ui/async-await/async-closures/signature-inference-from-two-part-bound.rs
@@ -0,0 +1,27 @@
+//@ edition: 2021
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+#![feature(async_closure)]
+
+use std::future::Future;
+use std::any::Any;
+
+struct Struct;
+impl Struct {
+    fn method(&self) {}
+}
+
+fn fake_async_closure<F, Fut>(_: F)
+where
+    F: Fn(Struct) -> Fut,
+    Fut: Future<Output = ()>,
+{}
+
+fn main() {
+    fake_async_closure(async |s| {
+        s.method();
+    })
+}
diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
index 3cc35b21409..b547da7126a 100644
--- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
+++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr
@@ -1,29 +1,29 @@
-error[E0311]: the parameter type `U` may not live long enough
+error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/async-generics-and-bounds.rs:9:5
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |            |
-   |     |            the parameter type `U` must be valid for the anonymous lifetime as defined here...
+   |     |            the parameter type `T` must be valid for the anonymous lifetime as defined here...
    |     ...so that the reference type `&(T, U)` does not outlive the data it points at
    |
 help: consider adding an explicit lifetime bound
    |
-LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, U: 'a;
+LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, T: 'a;
    |                 ++++  ++           ++                                       +++++++
 
-error[E0311]: the parameter type `T` may not live long enough
+error[E0311]: the parameter type `U` may not live long enough
   --> $DIR/async-generics-and-bounds.rs:9:5
    |
 LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |     |            |
-   |     |            the parameter type `T` must be valid for the anonymous lifetime as defined here...
+   |     |            the parameter type `U` must be valid for the anonymous lifetime as defined here...
    |     ...so that the reference type `&(T, U)` does not outlive the data it points at
    |
 help: consider adding an explicit lifetime bound
    |
-LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, T: 'a;
+LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, U: 'a;
    |                 ++++  ++           ++                                       +++++++
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr
index 3b27f8fe2f0..2e29a9bcc77 100644
--- a/tests/ui/async-await/in-trait/async-generics.stderr
+++ b/tests/ui/async-await/in-trait/async-generics.stderr
@@ -1,29 +1,29 @@
-error[E0311]: the parameter type `U` may not live long enough
+error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/async-generics.rs:6:5
    |
 LL |     async fn foo(&self) -> &(T, U);
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
    |     |            |
-   |     |            the parameter type `U` must be valid for the anonymous lifetime as defined here...
+   |     |            the parameter type `T` must be valid for the anonymous lifetime as defined here...
    |     ...so that the reference type `&(T, U)` does not outlive the data it points at
    |
 help: consider adding an explicit lifetime bound
    |
-LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a;
+LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: 'a;
    |                 ++++  ++           ++        +++++++++++
 
-error[E0311]: the parameter type `T` may not live long enough
+error[E0311]: the parameter type `U` may not live long enough
   --> $DIR/async-generics.rs:6:5
    |
 LL |     async fn foo(&self) -> &(T, U);
    |     ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^
    |     |            |
-   |     |            the parameter type `T` must be valid for the anonymous lifetime as defined here...
+   |     |            the parameter type `U` must be valid for the anonymous lifetime as defined here...
    |     ...so that the reference type `&(T, U)` does not outlive the data it points at
    |
 help: consider adding an explicit lifetime bound
    |
-LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where T: 'a;
+LL |     async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a;
    |                 ++++  ++           ++        +++++++++++
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/async-await/issue-61452.stderr b/tests/ui/async-await/issue-61452.stderr
index 3f623ba8ad2..b7b1e380c9e 100644
--- a/tests/ui/async-await/issue-61452.stderr
+++ b/tests/ui/async-await/issue-61452.stderr
@@ -13,12 +13,14 @@ error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/issue-61452.rs:9:5
    |
 LL | pub async fn g(x: usize) {
-   |                -
-   |                |
-   |                first assignment to `x`
-   |                help: consider making this binding mutable: `mut x`
+   |                - first assignment to `x`
 LL |     x += 1;
    |     ^^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL | pub async fn g(mut x: usize) {
+   |                +++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs
index 4090912f528..46b8fbf6f86 100644
--- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs
+++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs
@@ -9,7 +9,7 @@ trait HealthCheck {
 
 async fn do_health_check_par<HC>(hc: HC)
 where
-    HC: HealthCheck<check(): Send> + Send + 'static,
+    HC: HealthCheck<check(..): Send> + Send + 'static,
 {
     spawn(async move {
         let mut hc = hc;
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.rs b/tests/ui/async-await/return-type-notation/issue-110963-late.rs
index e0e59b6c6ad..cb9c0b97f1e 100644
--- a/tests/ui/async-await/return-type-notation/issue-110963-late.rs
+++ b/tests/ui/async-await/return-type-notation/issue-110963-late.rs
@@ -10,7 +10,7 @@ trait HealthCheck {
 
 async fn do_health_check_par<HC>(hc: HC)
 where
-    HC: HealthCheck<check(): Send> + Send + 'static,
+    HC: HealthCheck<check(..): Send> + Send + 'static,
 {
     spawn(async move {
         let mut hc = hc;
diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs
index bee9ad2516e..24041ed0807 100644
--- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs
+++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs
@@ -16,7 +16,7 @@ impl Foo for Bar {
     async fn bar(&self) {}
 }
 
-fn build<T>(_: T) where T: Foo<bar(): Send> {}
+fn build<T>(_: T) where T: Foo<bar(..): Send> {}
 
 fn main() {
     build(Bar);
diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs
index 365ca574006..2f6e04c3853 100644
--- a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs
+++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs
@@ -16,7 +16,7 @@ trait Foo {
     async fn bar(&self) -> i32;
 }
 
-trait SendFoo: Foo<bar(): Send> + Send {}
+trait SendFoo: Foo<bar(..): Send> + Send {}
 
 fn foobar(foo: impl SendFoo) -> JoinHandle<i32> {
     spawn(async move {
diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs
index 637678692bd..1e971d0aea7 100644
--- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs
+++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs
@@ -7,7 +7,7 @@ trait Super1<'a> {
     fn bar<'b>() -> bool;
 }
 
-impl Super1<'_, bar(): Send> for () {}
+impl Super1<'_, bar(..): Send> for () {}
 //~^ ERROR associated item constraints are not allowed here
 //~| ERROR not all trait items implemented
 
diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr
index 54960ae60bc..b23dbc37a55 100644
--- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr
+++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr
@@ -10,13 +10,13 @@ LL | #![feature(return_type_notation)]
 error[E0229]: associated item constraints are not allowed here
   --> $DIR/rtn-in-impl-signature.rs:10:17
    |
-LL | impl Super1<'_, bar(): Send> for () {}
-   |                 ^^^^^^^^^^^ associated item constraint not allowed here
+LL | impl Super1<'_, bar(..): Send> for () {}
+   |                 ^^^^^^^^^^^^^ associated item constraint not allowed here
    |
 help: consider removing this associated item constraint
    |
-LL | impl Super1<'_, bar(): Send> for () {}
-   |               ~~~~~~~~~~~~~
+LL | impl Super1<'_, bar(..): Send> for () {}
+   |               ~~~~~~~~~~~~~~~
 
 error[E0046]: not all trait items implemented, missing: `bar`
   --> $DIR/rtn-in-impl-signature.rs:10:1
@@ -24,8 +24,8 @@ error[E0046]: not all trait items implemented, missing: `bar`
 LL |     fn bar<'b>() -> bool;
    |     --------------------- `bar` from trait
 ...
-LL | impl Super1<'_, bar(): Send> for () {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation
+LL | impl Super1<'_, bar(..): Send> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs
index fa647ea0bc7..452568f3e46 100644
--- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs
+++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs
@@ -22,7 +22,7 @@ impl Foo for () {}
 
 fn test<T>()
 where
-    T: Foo<test(): Send>,
+    T: Foo<test(..): Send>,
     //~^ ERROR ambiguous associated function `test` in bounds of `Foo`
 {
 }
diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr
index 4003aad6d03..9a6fdd7f2ac 100644
--- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr
+++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr
@@ -16,8 +16,8 @@ LL |     async fn test();
 LL |     async fn test();
    |     ---------------- ambiguous `test` from `Super2`
 ...
-LL |     T: Foo<test(): Send>,
-   |            ^^^^^^^^^^^^ ambiguous associated function `test`
+LL |     T: Foo<test(..): Send>,
+   |            ^^^^^^^^^^^^^^ ambiguous associated function `test`
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.rs b/tests/ui/async-await/return-type-notation/super-method-bound.rs
index ad7ed5b283c..1aa8258a09b 100644
--- a/tests/ui/async-await/return-type-notation/super-method-bound.rs
+++ b/tests/ui/async-await/return-type-notation/super-method-bound.rs
@@ -16,7 +16,7 @@ impl Foo for () {}
 
 fn test<T>()
 where
-    T: Foo<test(): Send>,
+    T: Foo<test(..): Send>,
 {
 }
 
diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.rs b/tests/ui/async-await/return-type-notation/supertrait-bound.rs
index adb286a21d2..9c74c10b333 100644
--- a/tests/ui/async-await/return-type-notation/supertrait-bound.rs
+++ b/tests/ui/async-await/return-type-notation/supertrait-bound.rs
@@ -6,6 +6,6 @@
 trait IntFactory {
     fn stream(&self) -> impl Iterator<Item = i32>;
 }
-trait SendIntFactory: IntFactory<stream(): Send> + Send {}
+trait SendIntFactory: IntFactory<stream(..): Send> + Send {}
 
 fn main() {}
diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs
index 328cd8d2ad0..06a966df445 100644
--- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs
+++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs
@@ -11,7 +11,7 @@ trait Foo {
 
 fn test<T>()
 where
-    T: Foo<bar(): Send, baz(): Send>,
+    T: Foo<bar(..): Send, baz(..): Send>,
     //~^ ERROR return type notation is not allowed for functions that have const parameters
     //~| ERROR return type notation is not allowed for functions that have type parameters
 {
diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr
index da94d9d1e6d..1c000bc6c33 100644
--- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr
+++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr
@@ -13,17 +13,17 @@ error: return type notation is not allowed for functions that have type paramete
 LL |     async fn bar<T>() {}
    |                  - type parameter declared here
 ...
-LL |     T: Foo<bar(): Send, baz(): Send>,
-   |            ^^^^^^^^^^^
+LL |     T: Foo<bar(..): Send, baz(..): Send>,
+   |            ^^^^^^^^^^^^^
 
 error: return type notation is not allowed for functions that have const parameters
-  --> $DIR/ty-or-ct-params.rs:14:25
+  --> $DIR/ty-or-ct-params.rs:14:27
    |
 LL |     async fn baz<const N: usize>() {}
    |                  -------------- const parameter declared here
 ...
-LL |     T: Foo<bar(): Send, baz(): Send>,
-   |                         ^^^^^^^^^^^
+LL |     T: Foo<bar(..): Send, baz(..): Send>,
+   |                           ^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/borrowck/alias-liveness/rtn-static.rs b/tests/ui/borrowck/alias-liveness/rtn-static.rs
index 37f634a8e23..6aa5d8fc7a1 100644
--- a/tests/ui/borrowck/alias-liveness/rtn-static.rs
+++ b/tests/ui/borrowck/alias-liveness/rtn-static.rs
@@ -7,7 +7,7 @@ trait Foo {
     fn borrow(&mut self) -> impl Sized + '_;
 }
 
-fn live_past_borrow<T: Foo<borrow(): 'static>>(mut t: T) {
+fn live_past_borrow<T: Foo<borrow(..): 'static>>(mut t: T) {
     let x = t.borrow();
     drop(t);
     drop(x);
@@ -15,7 +15,7 @@ fn live_past_borrow<T: Foo<borrow(): 'static>>(mut t: T) {
 
 // Test that the `'_` item bound in `borrow` does not cause us to
 // overlook the `'static` RTN bound.
-fn overlapping_mut<T: Foo<borrow(): 'static>>(mut t: T) {
+fn overlapping_mut<T: Foo<borrow(..): 'static>>(mut t: T) {
     let x = t.borrow();
     let x = t.borrow();
 }
diff --git a/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr
index a7748209187..4b5b368287e 100644
--- a/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr
+++ b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr
@@ -12,11 +12,13 @@ LL |     let mut x = 0;
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrow-raw-address-of-mutability.rs:11:17
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     let mut f = || {
 LL |         let y = &raw mut x;
    |                 ^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
   --> $DIR/borrow-raw-address-of-mutability.rs:21:5
diff --git a/tests/ui/borrowck/borrowck-closures-unique.stderr b/tests/ui/borrowck/borrowck-closures-unique.stderr
index 23d3cc0e76f..613df9f2100 100644
--- a/tests/ui/borrowck/borrowck-closures-unique.stderr
+++ b/tests/ui/borrowck/borrowck-closures-unique.stderr
@@ -43,10 +43,13 @@ LL |     c1;
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/borrowck-closures-unique.rs:43:38
    |
-LL | fn e(x: &'static mut isize) {
-   |      - help: consider changing this to be mutable: `mut x`
 LL |     let c1 = |y: &'static mut isize| x = y;
    |                                      ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn e(mut x: &'static mut isize) {
+   |      +++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr
index 98ffa7f6ffa..e164ea44aa4 100644
--- a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr
+++ b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr
@@ -9,11 +9,11 @@ LL |             x += 1;
 help: consider making this binding mutable
    |
 LL |         mut x => {
-   |         ~~~~~
+   |         +++
 help: to modify the original value, take a borrow instead
    |
 LL |         ref mut x => {
-   |         ~~~~~~~~~
+   |         +++++++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/borrowck-match-binding-is-assignment.rs:20:13
@@ -26,11 +26,11 @@ LL |             x += 1;
 help: consider making this binding mutable
    |
 LL |         E::Foo(mut x) => {
-   |                ~~~~~
+   |                +++
 help: to modify the original value, take a borrow instead
    |
 LL |         E::Foo(ref mut x) => {
-   |                ~~~~~~~~~
+   |                +++++++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/borrowck-match-binding-is-assignment.rs:26:13
@@ -43,11 +43,11 @@ LL |             x += 1;
 help: consider making this binding mutable
    |
 LL |         S { bar: mut x } => {
-   |                  ~~~~~
+   |                  +++
 help: to modify the original value, take a borrow instead
    |
 LL |         S { bar: ref mut x } => {
-   |                  ~~~~~~~~~
+   |                  +++++++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/borrowck-match-binding-is-assignment.rs:32:13
@@ -60,11 +60,11 @@ LL |             x += 1;
 help: consider making this binding mutable
    |
 LL |         (mut x,) => {
-   |          ~~~~~
+   |          +++
 help: to modify the original value, take a borrow instead
    |
 LL |         (ref mut x,) => {
-   |          ~~~~~~~~~
+   |          +++++++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/borrowck-match-binding-is-assignment.rs:38:13
@@ -77,11 +77,11 @@ LL |             x += 1;
 help: consider making this binding mutable
    |
 LL |         [mut x,_,_] => {
-   |          ~~~~~
+   |          +++
 help: to modify the original value, take a borrow instead
    |
 LL |         [ref mut x,_,_] => {
-   |          ~~~~~~~~~
+   |          +++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/borrowck/immutable-arg.stderr b/tests/ui/borrowck/immutable-arg.stderr
index 84a480f6410..fb75172532f 100644
--- a/tests/ui/borrowck/immutable-arg.stderr
+++ b/tests/ui/borrowck/immutable-arg.stderr
@@ -1,10 +1,13 @@
 error[E0384]: cannot assign to immutable argument `_x`
   --> $DIR/immutable-arg.rs:2:5
    |
-LL | fn foo(_x: u32) {
-   |        -- help: consider making this binding mutable: `mut _x`
 LL |     _x = 4;
    |     ^^^^^^ cannot assign to immutable argument
+   |
+help: consider making this binding mutable
+   |
+LL | fn foo(mut _x: u32) {
+   |        +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-111554.stderr b/tests/ui/borrowck/issue-111554.stderr
index 6b7a42e4959..b3e8caae343 100644
--- a/tests/ui/borrowck/issue-111554.stderr
+++ b/tests/ui/borrowck/issue-111554.stderr
@@ -19,10 +19,13 @@ LL |         || bar(&mut self);
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
   --> $DIR/issue-111554.rs:21:16
    |
-LL |     pub fn quux(self) {
-   |                 ---- help: consider changing this to be mutable: `mut self`
 LL |         || bar(&mut self);
    |                ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     pub fn quux(mut self) {
+   |                 +++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/borrowck/issue-33819.stderr b/tests/ui/borrowck/issue-33819.stderr
index 41c9d6aac76..e5f6df26bc1 100644
--- a/tests/ui/borrowck/issue-33819.stderr
+++ b/tests/ui/borrowck/issue-33819.stderr
@@ -2,10 +2,13 @@ error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/issue-33819.rs:4:34
    |
 LL |         Some(ref v) => { let a = &mut v; },
-   |                                  ^^^^^^
-   |                                  |
-   |                                  cannot borrow as mutable
-   |                                  help: try removing `&mut` here
+   |                                  ^^^^^^ cannot borrow as mutable
+   |
+help: try removing `&mut` here
+   |
+LL -         Some(ref v) => { let a = &mut v; },
+LL +         Some(ref v) => { let a = v; },
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-45199.rs b/tests/ui/borrowck/issue-45199.rs
index ded46e56e34..b38967524fa 100644
--- a/tests/ui/borrowck/issue-45199.rs
+++ b/tests/ui/borrowck/issue-45199.rs
@@ -1,7 +1,7 @@
 fn test_drop_replace() {
     let b: Box<isize>;
     //~^ HELP consider making this binding mutable
-    //~| SUGGESTION mut b
+    //~| SUGGESTION mut
     b = Box::new(1);    //~ NOTE first assignment
     b = Box::new(2);    //~ ERROR cannot assign twice to immutable variable `b`
                         //~| NOTE cannot assign twice to immutable
@@ -10,13 +10,13 @@ fn test_drop_replace() {
 fn test_call() {
     let b = Box::new(1);    //~ NOTE first assignment
                             //~| HELP consider making this binding mutable
-                            //~| SUGGESTION mut b
+                            //~| SUGGESTION mut
     b = Box::new(2);        //~ ERROR cannot assign twice to immutable variable `b`
                             //~| NOTE cannot assign twice to immutable
 }
 
 fn test_args(b: Box<i32>) {  //~ HELP consider making this binding mutable
-                                //~| SUGGESTION mut b
+                                //~| SUGGESTION mut
     b = Box::new(2);            //~ ERROR cannot assign to immutable argument `b`
                                 //~| NOTE cannot assign to immutable argument
 }
diff --git a/tests/ui/borrowck/issue-45199.stderr b/tests/ui/borrowck/issue-45199.stderr
index 47aa3090827..8886e618e18 100644
--- a/tests/ui/borrowck/issue-45199.stderr
+++ b/tests/ui/borrowck/issue-45199.stderr
@@ -1,34 +1,40 @@
 error[E0384]: cannot assign twice to immutable variable `b`
   --> $DIR/issue-45199.rs:6:5
    |
-LL |     let b: Box<isize>;
-   |         - help: consider making this binding mutable: `mut b`
-...
 LL |     b = Box::new(1);
    |     - first assignment to `b`
 LL |     b = Box::new(2);
    |     ^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut b: Box<isize>;
+   |         +++
 
 error[E0384]: cannot assign twice to immutable variable `b`
   --> $DIR/issue-45199.rs:14:5
    |
 LL |     let b = Box::new(1);
-   |         -
-   |         |
-   |         first assignment to `b`
-   |         help: consider making this binding mutable: `mut b`
+   |         - first assignment to `b`
 ...
 LL |     b = Box::new(2);
    |     ^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut b = Box::new(1);
+   |         +++
 
 error[E0384]: cannot assign to immutable argument `b`
   --> $DIR/issue-45199.rs:20:5
    |
-LL | fn test_args(b: Box<i32>) {
-   |              - help: consider making this binding mutable: `mut b`
-LL |
 LL |     b = Box::new(2);
    |     ^ cannot assign to immutable argument
+   |
+help: consider making this binding mutable
+   |
+LL | fn test_args(mut b: Box<i32>) {
+   |              +++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
index 098a2964e9f..ff5ec1db346 100644
--- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
+++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
@@ -44,56 +44,68 @@ LL |         borrowck_closures_unique::e(addr_of_mut!(X));
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:9:46
    |
-LL |     pub fn e(x: &'static mut isize) {
-   |              - help: consider changing this to be mutable: `mut x`
-LL |         static mut Y: isize = 3;
 LL |         let mut c1 = |y: &'static mut isize| x = y;
    |                                              ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     pub fn e(mut x: &'static mut isize) {
+   |              +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:22:50
    |
-LL |     pub fn ee(x: &'static mut isize) {
-   |               - help: consider changing this to be mutable: `mut x`
-...
 LL |             let mut c2 = |y: &'static mut isize| x = y;
    |                                                  ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     pub fn ee(mut x: &'static mut isize) {
+   |               +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:37:13
    |
-LL |     pub fn capture_assign_whole(x: (i32,)) {
-   |                                 - help: consider changing this to be mutable: `mut x`
-LL |         || {
 LL |             x = (1,);
    |             ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     pub fn capture_assign_whole(mut x: (i32,)) {
+   |                                 +++
 
 error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:43:13
    |
-LL |     pub fn capture_assign_part(x: (i32,)) {
-   |                                - help: consider changing this to be mutable: `mut x`
-LL |         || {
 LL |             x.0 = 1;
    |             ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     pub fn capture_assign_part(mut x: (i32,)) {
+   |                                +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:49:13
    |
-LL |     pub fn capture_reborrow_whole(x: (i32,)) {
-   |                                   - help: consider changing this to be mutable: `mut x`
-LL |         || {
 LL |             &mut x;
    |             ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     pub fn capture_reborrow_whole(mut x: (i32,)) {
+   |                                   +++
 
 error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:13
    |
-LL |     pub fn capture_reborrow_part(x: (i32,)) {
-   |                                  - help: consider changing this to be mutable: `mut x`
-LL |         || {
 LL |             &mut x.0;
    |             ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     pub fn capture_reborrow_part(mut x: (i32,)) {
+   |                                  +++
 
 error: aborting due to 6 previous errors; 3 warnings emitted
 
diff --git a/tests/ui/borrowck/mutability-errors.stderr b/tests/ui/borrowck/mutability-errors.stderr
index b39e57d70ec..3cab3ccb993 100644
--- a/tests/ui/borrowck/mutability-errors.stderr
+++ b/tests/ui/borrowck/mutability-errors.stderr
@@ -262,74 +262,90 @@ LL | fn imm_local(mut x: (i32,)) {
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/mutability-errors.rs:60:9
    |
-LL | fn imm_capture(x: (i32,)) {
-   |                - help: consider changing this to be mutable: `mut x`
-LL |     || {
 LL |         x = (1,);
    |         ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_capture(mut x: (i32,)) {
+   |                +++
 
 error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
   --> $DIR/mutability-errors.rs:61:9
    |
-LL | fn imm_capture(x: (i32,)) {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |         x.0 = 1;
    |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_capture(mut x: (i32,)) {
+   |                +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/mutability-errors.rs:62:9
    |
-LL | fn imm_capture(x: (i32,)) {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |         &mut x;
    |         ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_capture(mut x: (i32,)) {
+   |                +++
 
 error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
   --> $DIR/mutability-errors.rs:63:9
    |
-LL | fn imm_capture(x: (i32,)) {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |         &mut x.0;
    |         ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_capture(mut x: (i32,)) {
+   |                +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/mutability-errors.rs:66:9
    |
-LL | fn imm_capture(x: (i32,)) {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |         x = (1,);
    |         ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_capture(mut x: (i32,)) {
+   |                +++
 
 error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
   --> $DIR/mutability-errors.rs:67:9
    |
-LL | fn imm_capture(x: (i32,)) {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |         x.0 = 1;
    |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_capture(mut x: (i32,)) {
+   |                +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/mutability-errors.rs:68:9
    |
-LL | fn imm_capture(x: (i32,)) {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |         &mut x;
    |         ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_capture(mut x: (i32,)) {
+   |                +++
 
 error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
   --> $DIR/mutability-errors.rs:69:9
    |
-LL | fn imm_capture(x: (i32,)) {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |         &mut x.0;
    |         ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_capture(mut x: (i32,)) {
+   |                +++
 
 error[E0594]: cannot assign to immutable static item `X`
   --> $DIR/mutability-errors.rs:76:5
diff --git a/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr b/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr
index fd2a775a099..aec3d663160 100644
--- a/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr
+++ b/tests/ui/borrowck/suggest-ref-mut-issue-118596.stderr
@@ -9,11 +9,11 @@ LL |         x = 2;
 help: consider making this binding mutable
    |
 LL |     if let Some(mut x) = y {
-   |                 ~~~~~
+   |                 +++
 help: to modify the original value, take a borrow instead
    |
 LL |     if let Some(ref mut x) = y {
-   |                 ~~~~~~~~~
+   |                 +++++++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/suggest-ref-mut-issue-118596.rs:9:5
@@ -26,11 +26,11 @@ LL |     x = 0;
 help: consider making this binding mutable
    |
 LL |     let [mut x, ref xs_hold @ ..] = arr;
-   |          ~~~~~
+   |          +++
 help: to modify the original value, take a borrow instead
    |
 LL |     let [ref mut x, ref xs_hold @ ..] = arr;
-   |          ~~~~~~~~~
+   |          +++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/tainted-promoteds.stderr b/tests/ui/borrowck/tainted-promoteds.stderr
index a5c448fdcdb..04669a29097 100644
--- a/tests/ui/borrowck/tainted-promoteds.stderr
+++ b/tests/ui/borrowck/tainted-promoteds.stderr
@@ -2,12 +2,14 @@ error[E0384]: cannot assign twice to immutable variable `a`
   --> $DIR/tainted-promoteds.rs:7:5
    |
 LL |     let a = 0;
-   |         -
-   |         |
-   |         first assignment to `a`
-   |         help: consider making this binding mutable: `mut a`
+   |         - first assignment to `a`
 LL |     a = &0 * &1 * &2 * &3;
    |     ^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut a = 0;
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/cannot-mutate-captured-non-mut-var.stderr b/tests/ui/cannot-mutate-captured-non-mut-var.stderr
index 2d6e83c9e82..8d794f8251f 100644
--- a/tests/ui/cannot-mutate-captured-non-mut-var.stderr
+++ b/tests/ui/cannot-mutate-captured-non-mut-var.stderr
@@ -1,18 +1,24 @@
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/cannot-mutate-captured-non-mut-var.rs:9:25
    |
-LL |     let x = 1;
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     to_fn_once(move|| { x = 2; });
    |                         ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 1;
+   |         +++
 
 error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable
   --> $DIR/cannot-mutate-captured-non-mut-var.rs:13:25
    |
-LL |     let s = std::io::stdin();
-   |         - help: consider changing this to be mutable: `mut s`
 LL |     to_fn_once(move|| { s.read_to_end(&mut Vec::new()); });
    |                         ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut s = std::io::stdin();
+   |         +++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs
index 0d8f92f013f..5704a33cc87 100644
--- a/tests/ui/cast/cast-rfc0401-vtable-kinds.rs
+++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.rs
@@ -4,25 +4,12 @@
 
 #![feature(unsized_tuple_coercion)]
 
-trait Foo<T> {
-    fn foo(&self, _: T) -> u32 { 42 }
-}
-
 trait Bar { //~ WARN trait `Bar` is never used
     fn bar(&self) { println!("Bar!"); }
 }
 
-impl<T> Foo<T> for () {}
-impl Foo<u32> for u32 { fn foo(&self, _: u32) -> u32 { self+43 } }
 impl Bar for () {}
 
-unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo<u32>+'a)) -> u32 {
-    let foo_e : *const dyn Foo<u32> = t as *const _;
-    let r_1 = foo_e as *mut dyn Foo<u32>;
-
-    (&*r_1).foo(0)
-}
-
 #[repr(C)]
 struct FooS<T:?Sized>(T);
 #[repr(C)]
@@ -38,11 +25,6 @@ fn tuple_i32_to_u32<T:?Sized>(u: *const (i32, T)) -> *const (u32, T) {
 
 
 fn main() {
-    let x = 4u32;
-    let y : &dyn Foo<u32> = &x;
-    let fl = unsafe { round_trip_and_call(y as *const dyn Foo<u32>) };
-    assert_eq!(fl, (43+4));
-
     let s = FooS([0,1,2]);
     let u: &FooS<[u32]> = &s;
     let u: *const FooS<[u32]> = u;
diff --git a/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr
index 952687e98d0..4f57e2e7df7 100644
--- a/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr
+++ b/tests/ui/cast/cast-rfc0401-vtable-kinds.stderr
@@ -1,5 +1,5 @@
 warning: trait `Bar` is never used
-  --> $DIR/cast-rfc0401-vtable-kinds.rs:11:7
+  --> $DIR/cast-rfc0401-vtable-kinds.rs:7:7
    |
 LL | trait Bar {
    |       ^^^
diff --git a/tests/ui/cast/ptr-to-trait-obj-add-auto.rs b/tests/ui/cast/ptr-to-trait-obj-add-auto.rs
new file mode 100644
index 00000000000..46e72ea0877
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-add-auto.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+
+trait Trait<'a> {}
+
+fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) {
+    x as _
+    //~^ warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
+    //~| warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+}
+
+// (to test diagnostic list formatting)
+fn add_multiple_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send + Sync + Unpin) {
+    x as _
+    //~^ warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
+    //~| warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+}
+
+fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-add-auto.stderr b/tests/ui/cast/ptr-to-trait-obj-add-auto.stderr
new file mode 100644
index 00000000000..e5ef8bf76b4
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-add-auto.stderr
@@ -0,0 +1,43 @@
+warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
+  --> $DIR/ptr-to-trait-obj-add-auto.rs:6:5
+   |
+LL |     x as _
+   |     ^^^^^^
+   |
+   = 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 #127323 <https://github.com/rust-lang/rust/issues/127323>
+   = note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
+
+warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
+  --> $DIR/ptr-to-trait-obj-add-auto.rs:13:5
+   |
+LL |     x as _
+   |     ^^^^^^
+   |
+   = 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 #127323 <https://github.com/rust-lang/rust/issues/127323>
+
+warning: 2 warnings emitted
+
+Future incompatibility report: Future breakage diagnostic:
+warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
+  --> $DIR/ptr-to-trait-obj-add-auto.rs:6:5
+   |
+LL |     x as _
+   |     ^^^^^^
+   |
+   = 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 #127323 <https://github.com/rust-lang/rust/issues/127323>
+   = note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
+
+Future breakage diagnostic:
+warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
+  --> $DIR/ptr-to-trait-obj-add-auto.rs:13:5
+   |
+LL |     x as _
+   |     ^^^^^^
+   |
+   = 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 #127323 <https://github.com/rust-lang/rust/issues/127323>
+   = note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
+
diff --git a/tests/ui/cast/ptr-to-trait-obj-add-super-auto.rs b/tests/ui/cast/ptr-to-trait-obj-add-super-auto.rs
new file mode 100644
index 00000000000..ac8108d8ec4
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-add-super-auto.rs
@@ -0,0 +1,9 @@
+//@ check-pass
+
+trait Trait: Send {}
+impl Trait for () {}
+
+fn main() {
+    // This is OK: `Trait` has `Send` super trait.
+    &() as *const dyn Trait as *const (dyn Trait + Send);
+}
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.rs b/tests/ui/cast/ptr-to-trait-obj-different-args.rs
new file mode 100644
index 00000000000..c6038cfe864
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-args.rs
@@ -0,0 +1,37 @@
+//@ check-fail
+//
+// issue: <https://github.com/rust-lang/rust/issues/120222>
+
+trait A {}
+impl<T> A for T {}
+trait B {}
+impl<T> B for T {}
+
+trait Trait<G> {}
+struct X;
+impl<T> Trait<X> for T {}
+struct Y;
+impl<T> Trait<Y> for T {}
+
+fn main() {
+    let a: *const dyn A = &();
+    let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
+
+    let x: *const dyn Trait<X> = &();
+    let y: *const dyn Trait<Y> = x as _; //~ error: mismatched types
+
+    _ = (b, y);
+}
+
+fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
+    let _: *const dyn Trait<T> = x as _; //~ error: mismatched types
+    let _: *const dyn Trait<X> = t as _; //~ error: mismatched types
+}
+
+trait Assocked {
+    type Assoc: ?Sized;
+}
+
+fn change_assoc(x: *mut dyn Assocked<Assoc = u8>) -> *mut dyn Assocked<Assoc = u32> {
+    x as _ //~ error: mismatched types
+}
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
new file mode 100644
index 00000000000..b04289ae747
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
@@ -0,0 +1,53 @@
+error[E0606]: casting `*const dyn A` as `*const dyn B` is invalid
+  --> $DIR/ptr-to-trait-obj-different-args.rs:18:27
+   |
+LL |     let b: *const dyn B = a as _;
+   |                           ^^^^^^
+   |
+   = note: vtable kinds may not match
+
+error[E0308]: mismatched types
+  --> $DIR/ptr-to-trait-obj-different-args.rs:21:34
+   |
+LL |     let y: *const dyn Trait<Y> = x as _;
+   |                                  ^^^^^^ expected `X`, found `Y`
+   |
+   = note: expected trait object `dyn Trait<X>`
+              found trait object `dyn Trait<Y>`
+
+error[E0308]: mismatched types
+  --> $DIR/ptr-to-trait-obj-different-args.rs:27:34
+   |
+LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
+   |            - found this type parameter
+LL |     let _: *const dyn Trait<T> = x as _;
+   |                                  ^^^^^^ expected `X`, found type parameter `T`
+   |
+   = note: expected trait object `dyn Trait<X>`
+              found trait object `dyn Trait<T>`
+
+error[E0308]: mismatched types
+  --> $DIR/ptr-to-trait-obj-different-args.rs:28:34
+   |
+LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
+   |            - expected this type parameter
+LL |     let _: *const dyn Trait<T> = x as _;
+LL |     let _: *const dyn Trait<X> = t as _;
+   |                                  ^^^^^^ expected type parameter `T`, found `X`
+   |
+   = note: expected trait object `dyn Trait<T>`
+              found trait object `dyn Trait<X>`
+
+error[E0308]: mismatched types
+  --> $DIR/ptr-to-trait-obj-different-args.rs:36:5
+   |
+LL |     x as _
+   |     ^^^^^^ expected `u8`, found `u32`
+   |
+   = note: expected trait object `dyn Assocked<Assoc = u8>`
+              found trait object `dyn Assocked<Assoc = u32>`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0308, E0606.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs
new file mode 100644
index 00000000000..cdd55e24392
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs
@@ -0,0 +1,27 @@
+//@ check-fail
+//
+// Make sure we can't trick the compiler by using a projection.
+
+trait Cat<'a> {}
+impl Cat<'_> for () {}
+
+trait Id {
+    type Id: ?Sized;
+}
+impl<T: ?Sized> Id for T {
+    type Id = T;
+}
+
+struct S<T: ?Sized> {
+    tail: <T as Id>::Id,
+}
+
+fn m<'a>() {
+    let unsend: *const dyn Cat<'a> = &();
+    let _send = unsend as *const S<dyn Cat<'static>>;
+    //~^ error: lifetime may not live long enough
+}
+
+fn main() {
+    m();
+}
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr
new file mode 100644
index 00000000000..d1d598e603f
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:21:17
+   |
+LL | fn m<'a>() {
+   |      -- lifetime `'a` defined here
+LL |     let unsend: *const dyn Cat<'a> = &();
+LL |     let _send = unsend as *const S<dyn Cat<'static>>;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type `S<dyn Cat<'_>>`, which makes the generic argument `dyn Cat<'_>` invariant
+   = note: the struct `S<T>` is invariant over the parameter `T`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
new file mode 100644
index 00000000000..96345de01c9
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.rs
@@ -0,0 +1,31 @@
+//@ check-fail
+//
+// issue: <https://github.com/rust-lang/rust/issues/120217>
+
+#![feature(arbitrary_self_types)]
+
+trait Static<'a> {
+    fn proof(self: *const Self, s: &'a str) -> &'static str;
+}
+
+fn bad_cast<'a>(x: *const dyn Static<'static>) -> *const dyn Static<'a> {
+    x as _ //~ error: lifetime may not live long enough
+}
+
+impl Static<'static> for () {
+    fn proof(self: *const Self, s: &'static str) -> &'static str {
+        s
+    }
+}
+
+fn extend_lifetime(s: &str) -> &'static str {
+    bad_cast(&()).proof(s)
+}
+
+fn main() {
+    let s = String::from("Hello World");
+    let slice = extend_lifetime(&s);
+    println!("Now it exists: {slice}");
+    drop(s);
+    println!("Now it’s gone: {slice}");
+}
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr
new file mode 100644
index 00000000000..b7319e3356b
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-lt-ext.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-lt-ext.rs:12:5
+   |
+LL | fn bad_cast<'a>(x: *const dyn Static<'static>) -> *const dyn Static<'a> {
+   |             -- lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
new file mode 100644
index 00000000000..01c347bfae5
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
@@ -0,0 +1,37 @@
+//@ check-fail
+
+trait Trait<'a> {}
+
+fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+    x as _ //~ error: lifetime may not live long enough
+           //~| error: lifetime may not live long enough
+}
+
+fn change_lt_ab<'a: 'b, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+    x as _ //~ error: lifetime may not live long enough
+}
+
+fn change_lt_ba<'a, 'b: 'a>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+    x as _ //~ error: lifetime may not live long enough
+}
+
+trait Assocked {
+    type Assoc: ?Sized;
+}
+
+fn change_assoc_0<'a, 'b>(
+    x: *mut dyn Assocked<Assoc = dyn Send + 'a>,
+) -> *mut dyn Assocked<Assoc = dyn Send + 'b> {
+    x as _ //~ error: lifetime may not live long enough
+           //~| error: lifetime may not live long enough
+}
+
+fn change_assoc_1<'a, 'b>(
+    x: *mut dyn Assocked<Assoc = dyn Trait<'a>>,
+) -> *mut dyn Assocked<Assoc = dyn Trait<'b>> {
+    x as _ //~ error: lifetime may not live long enough
+           //~| error: lifetime may not live long enough
+}
+
+
+fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
new file mode 100644
index 00000000000..7044e4dec1f
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
@@ -0,0 +1,136 @@
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:6:5
+   |
+LL | fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+   |              --  -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:6:5
+   |
+LL | fn change_lt<'a, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+   |              --  -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'b` and `'a` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:11:5
+   |
+LL | fn change_lt_ab<'a: 'b, 'b>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+   |                 --      -- lifetime `'b` defined here
+   |                 |
+   |                 lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:15:5
+   |
+LL | fn change_lt_ba<'a, 'b: 'a>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
+   |                 --  -- lifetime `'b` defined here
+   |                 |
+   |                 lifetime `'a` defined here
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to `dyn Trait<'_>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5
+   |
+LL | fn change_assoc_0<'a, 'b>(
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Send>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5
+   |
+LL | fn change_assoc_0<'a, 'b>(
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Send>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'b` and `'a` must be the same: replace one with the other
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5
+   |
+LL | fn change_assoc_1<'a, 'b>(
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Trait<'_>>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5
+   |
+LL | fn change_assoc_1<'a, 'b>(
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     x as _
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to `dyn Assocked<Assoc = dyn Trait<'_>>`
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+help: `'b` and `'a` must be the same: replace one with the other
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/cast/ptr-to-trait-obj-ok.rs b/tests/ui/cast/ptr-to-trait-obj-ok.rs
new file mode 100644
index 00000000000..656c99c58dc
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-ok.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+
+trait Trait<'a> {}
+
+fn remove_auto<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut dyn Trait<'a> {
+    x as _
+}
+
+fn cast_inherent_lt<'a, 'b>(x: *mut (dyn Trait<'static> + 'a)) -> *mut (dyn Trait<'static> + 'b) {
+    x as _
+}
+
+fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) {
+    x as _
+}
+
+fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs
new file mode 100644
index 00000000000..ff2c4cacfb1
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs
@@ -0,0 +1,14 @@
+trait Super {}
+trait Sub: Super {}
+
+struct Wrapper<T: ?Sized>(T);
+
+// This cast should not compile.
+// Upcasting can't work here, because we are also changing the type (`Wrapper`),
+// and reinterpreting would be confusing/surprising.
+// See <https://github.com/rust-lang/rust/pull/120248#discussion_r1487739518>
+fn cast(ptr: *const dyn Sub) -> *const Wrapper<dyn Super> {
+    ptr as _ //~ error: casting `*const (dyn Sub + 'static)` as `*const Wrapper<dyn Super>` is invalid
+}
+
+fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr
new file mode 100644
index 00000000000..38c8ba96bc5
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr
@@ -0,0 +1,11 @@
+error[E0606]: casting `*const (dyn Sub + 'static)` as `*const Wrapper<dyn Super>` is invalid
+  --> $DIR/ptr-to-trait-obj-wrap-upcast.rs:11:5
+   |
+LL |     ptr as _
+   |     ^^^^^^^^
+   |
+   = note: vtable kinds may not match
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/tests/ui/closures/2229_closure_analysis/array_subslice.stderr b/tests/ui/closures/2229_closure_analysis/array_subslice.stderr
index 888c60d5e91..ee941caa773 100644
--- a/tests/ui/closures/2229_closure_analysis/array_subslice.stderr
+++ b/tests/ui/closures/2229_closure_analysis/array_subslice.stderr
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `x[..]` as mutable, as `x` is not declared as mutable
   --> $DIR/array_subslice.rs:7:21
    |
-LL | pub fn subslice_array(x: [u8; 3]) {
-   |                       - help: consider changing this to be mutable: `mut x`
-...
 LL |         let [ref y, ref mut z @ ..] = x;
    |                     ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | pub fn subslice_array(mut x: [u8; 3]) {
+   |                       +++
 
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
   --> $DIR/array_subslice.rs:10:5
diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
index 98414fa8a3d..6f5043ef08d 100644
--- a/tests/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
+++ b/tests/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
@@ -1,20 +1,24 @@
 error[E0594]: cannot assign to `z.0.0.0`, as it is not declared as mutable
   --> $DIR/cant-mutate-imm.rs:12:9
    |
-LL |     let z = (y, 10);
-   |         - help: consider changing this to be mutable: `mut z`
-...
 LL |         z.0.0.0 = 20;
    |         ^^^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut z = (y, 10);
+   |         +++
 
 error[E0594]: cannot assign to `*bx.0`, as it is not declared as mutable
   --> $DIR/cant-mutate-imm.rs:24:9
    |
-LL |     let bx = Box::new(x);
-   |         -- help: consider changing this to be mutable: `mut bx`
-...
 LL |         bx.0 = 20;
    |         ^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut bx = Box::new(x);
+   |         +++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs b/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs
index f46ec4b927a..4da87038577 100644
--- a/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs
+++ b/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs
@@ -48,7 +48,7 @@ impl Drop for ContainsAndImplsDrop {
 }
 
 // If a path isn't directly captured but requires Drop, then this tests that migrations aren't
-// needed if the a parent to that path is captured.
+// needed if the parent to that path is captured.
 fn test_precise_analysis_parent_captured_1() {
     let t = ConstainsDropField(Foo(10), Foo(20));
 
@@ -60,7 +60,7 @@ fn test_precise_analysis_parent_captured_1() {
 }
 
 // If a path isn't directly captured but requires Drop, then this tests that migrations aren't
-// needed if the a parent to that path is captured.
+// needed if the parent to that path is captured.
 fn test_precise_analysis_parent_captured_2() {
     let t = ContainsAndImplsDrop(Foo(10));
 
diff --git a/tests/ui/closures/closure-immutable-outer-variable.stderr b/tests/ui/closures/closure-immutable-outer-variable.stderr
index 23bd0020db6..c4b0e544957 100644
--- a/tests/ui/closures/closure-immutable-outer-variable.stderr
+++ b/tests/ui/closures/closure-immutable-outer-variable.stderr
@@ -1,10 +1,13 @@
 error[E0594]: cannot assign to `y`, as it is not declared as mutable
   --> $DIR/closure-immutable-outer-variable.rs:11:26
    |
-LL |     let y = true;
-   |         - help: consider changing this to be mutable: `mut y`
 LL |     foo(Box::new(move || y = !y) as Box<_>);
    |                          ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut y = true;
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.rs b/tests/ui/closures/issue-72408-nested-closures-exponential.rs
index 682508f9280..033e4224338 100644
--- a/tests/ui/closures/issue-72408-nested-closures-exponential.rs
+++ b/tests/ui/closures/issue-72408-nested-closures-exponential.rs
@@ -1,5 +1,4 @@
-//@ build-pass
-//@ ignore-compare-mode-next-solver (hangs)
+//@ build-fail
 
 // Closures include captured types twice in a type tree.
 //
@@ -46,6 +45,7 @@ fn main() {
 
     let f = dup(f);
     let f = dup(f);
+    //~^ ERROR reached the type-length limit
     let f = dup(f);
     let f = dup(f);
     let f = dup(f);
diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.stderr b/tests/ui/closures/issue-72408-nested-closures-exponential.stderr
new file mode 100644
index 00000000000..2120b456963
--- /dev/null
+++ b/tests/ui/closures/issue-72408-nested-closures-exponential.stderr
@@ -0,0 +1,10 @@
+error: reached the type-length limit while instantiating `dup::<{closure@$DIR/issue-72408-nested-closures-exponential.rs:13:5: 13:13}>`
+  --> $DIR/issue-72408-nested-closures-exponential.rs:47:13
+   |
+LL |     let f = dup(f);
+   |             ^^^^^^
+   |
+   = help: consider adding a `#![type_length_limit="29360121"]` attribute to your crate
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs
index 919f1a8120e..4d3f2c18dc8 100644
--- a/tests/ui/codegen/overflow-during-mono.rs
+++ b/tests/ui/codegen/overflow-during-mono.rs
@@ -1,5 +1,5 @@
 //@ build-fail
-//~^ ERROR overflow evaluating the requirement
+//@ error-pattern: reached the type-length limit while instantiating
 
 #![recursion_limit = "32"]
 
diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr
index f7a3e2df3db..e06fcd28966 100644
--- a/tests/ui/codegen/overflow-during-mono.stderr
+++ b/tests/ui/codegen/overflow-during-mono.stderr
@@ -1,11 +1,8 @@
-error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized`
+error: reached the type-length limit while instantiating `<Filter<Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, ...> as Iterator>::try_fold::<..., ..., ...>`
+  --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
    |
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`)
-   = note: required for `Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator`
-   = note: 31 redundant requirements hidden
-   = note: required for `Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator`
-   = note: required for `Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `IntoIterator`
+   = help: consider adding a `#![type_length_limit="20156994"]` attribute to your crate
+   = note: the full type name has been written to '$TEST_BUILD_DIR/codegen/overflow-during-mono/overflow-during-mono.long-type.txt'
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/command-line-diagnostics.stderr b/tests/ui/command-line-diagnostics.stderr
index b719a00ad5d..6d33fb4172f 100644
--- a/tests/ui/command-line-diagnostics.stderr
+++ b/tests/ui/command-line-diagnostics.stderr
@@ -2,12 +2,14 @@ error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/command-line-diagnostics.rs:6:5
    |
 LL |     let x = 42;
-   |         -
-   |         |
-   |         first assignment to `x`
-   |         help: consider making this binding mutable: `mut x`
+   |         - first assignment to `x`
 LL |     x = 43;
    |     ^^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut x = 42;
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/compare-method/bad-self-type.stderr b/tests/ui/compare-method/bad-self-type.stderr
index a87b713c2b4..a3a31f43447 100644
--- a/tests/ui/compare-method/bad-self-type.stderr
+++ b/tests/ui/compare-method/bad-self-type.stderr
@@ -2,22 +2,20 @@ error[E0053]: method `poll` has an incompatible type for trait
   --> $DIR/bad-self-type.rs:10:13
    |
 LL |     fn poll(self, _: &mut Context<'_>) -> Poll<()> {
-   |             ^^^^
-   |             |
-   |             expected `Pin<&mut MyFuture>`, found `MyFuture`
-   |             help: change the self-receiver type to match the trait: `self: Pin<&mut MyFuture>`
+   |             ^^^^ expected `Pin<&mut MyFuture>`, found `MyFuture`
    |
    = note: expected signature `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>`
               found signature `fn(MyFuture, &mut Context<'_>) -> Poll<_>`
+help: change the self-receiver type to match the trait
+   |
+LL |     fn poll(self: Pin<&mut MyFuture>, _: &mut Context<'_>) -> Poll<()> {
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0053]: method `foo` has an incompatible type for trait
   --> $DIR/bad-self-type.rs:22:18
    |
 LL |     fn foo(self: Box<Self>) {}
-   |            ------^^^^^^^^^
-   |            |     |
-   |            |     expected `MyFuture`, found `Box<MyFuture>`
-   |            help: change the self-receiver type to match the trait: `self`
+   |                  ^^^^^^^^^ expected `MyFuture`, found `Box<MyFuture>`
    |
 note: type in trait
   --> $DIR/bad-self-type.rs:17:12
@@ -26,6 +24,10 @@ LL |     fn foo(self);
    |            ^^^^
    = note: expected signature `fn(MyFuture)`
               found signature `fn(Box<MyFuture>)`
+help: change the self-receiver type to match the trait
+   |
+LL |     fn foo(self) {}
+   |            ~~~~
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/bad-self-type.rs:24:17
@@ -39,7 +41,7 @@ note: type in trait
 LL |     fn bar(self) -> Option<()>;
    |                     ^^^^^^^^^^
    = note: expected signature `fn(MyFuture) -> Option<()>`
-              found signature `fn(MyFuture)`
+              found signature `fn(MyFuture) -> ()`
 help: change the output type to match the trait
    |
 LL |     fn bar(self) -> Option<()> {}
diff --git a/tests/ui/compare-method/issue-90444.stderr b/tests/ui/compare-method/issue-90444.stderr
index 52e23d03b14..f05c9939c00 100644
--- a/tests/ui/compare-method/issue-90444.stderr
+++ b/tests/ui/compare-method/issue-90444.stderr
@@ -2,25 +2,27 @@ error[E0053]: method `from` has an incompatible type for trait
   --> $DIR/issue-90444.rs:3:16
    |
 LL |     fn from(_: fn((), (), &mut ())) -> Self {
-   |                ^^^^^^^^^^^^^^^^^^^
-   |                |
-   |                types differ in mutability
-   |                help: change the parameter type to match the trait: `for<'a> fn((), (), &'a ())`
+   |                ^^^^^^^^^^^^^^^^^^^ types differ in mutability
    |
    = note: expected signature `fn(for<'a> fn((), (), &'a ())) -> A`
               found signature `fn(for<'a> fn((), (), &'a mut ())) -> A`
+help: change the parameter type to match the trait
+   |
+LL |     fn from(_: for<'a> fn((), (), &'a ())) -> Self {
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0053]: method `from` has an incompatible type for trait
   --> $DIR/issue-90444.rs:11:16
    |
 LL |     fn from(_: fn((), (), u64)) -> Self {
-   |                ^^^^^^^^^^^^^^^
-   |                |
-   |                expected `u32`, found `u64`
-   |                help: change the parameter type to match the trait: `fn((), (), u32)`
+   |                ^^^^^^^^^^^^^^^ expected `u32`, found `u64`
    |
    = note: expected signature `fn(fn((), (), u32)) -> B`
               found signature `fn(fn((), (), u64)) -> B`
+help: change the parameter type to match the trait
+   |
+LL |     fn from(_: fn((), (), u32)) -> Self {
+   |                ~~~~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/compare-method/reordered-type-param.stderr b/tests/ui/compare-method/reordered-type-param.stderr
index 8a439acee13..1e8266e213d 100644
--- a/tests/ui/compare-method/reordered-type-param.stderr
+++ b/tests/ui/compare-method/reordered-type-param.stderr
@@ -2,10 +2,8 @@ error[E0053]: method `b` has an incompatible type for trait
   --> $DIR/reordered-type-param.rs:16:30
    |
 LL |   fn b<F:Clone,G>(&self, _x: G) -> G { panic!() }
-   |        -       -             ^
-   |        |       |             |
-   |        |       |             expected type parameter `F`, found type parameter `G`
-   |        |       |             help: change the parameter type to match the trait: `F`
+   |        -       -             ^ expected type parameter `F`, found type parameter `G`
+   |        |       |
    |        |       found type parameter
    |        expected type parameter
    |
@@ -18,6 +16,10 @@ LL |   fn b<C:Clone,D>(&self, x: C) -> C;
               found signature `fn(&E, G) -> G`
    = 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
+help: change the parameter type to match the trait
+   |
+LL |   fn b<F:Clone,G>(&self, _x: F) -> G { panic!() }
+   |                              ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs
new file mode 100644
index 00000000000..9f05c53eef0
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs
@@ -0,0 +1,18 @@
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+
+use std::marker::ConstParamTy;
+
+#[derive(ConstParamTy)]
+//~^ the trait `ConstParamTy` cannot be implemented for this ty
+struct Foo([*const u8; 1]);
+
+#[derive(ConstParamTy)]
+//~^ the trait `ConstParamTy` cannot be implemented for this ty
+struct Foo2([*mut u8; 1]);
+
+#[derive(ConstParamTy)]
+//~^ the trait `ConstParamTy` cannot be implemented for this ty
+struct Foo3([fn(); 1]);
+
+fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr
new file mode 100644
index 00000000000..9e772e8d55d
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr
@@ -0,0 +1,51 @@
+error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
+  --> $DIR/nested_bad_const_param_ty.rs:6:10
+   |
+LL | #[derive(ConstParamTy)]
+   |          ^^^^^^^^^^^^
+LL |
+LL | struct Foo([*const u8; 1]);
+   |            -------------- this field does not implement `ConstParamTy`
+   |
+note: the `ConstParamTy` impl for `[*const u8; 1]` requires that `*const u8: ConstParamTy`
+  --> $DIR/nested_bad_const_param_ty.rs:8:12
+   |
+LL | struct Foo([*const u8; 1]);
+   |            ^^^^^^^^^^^^^^
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
+  --> $DIR/nested_bad_const_param_ty.rs:10:10
+   |
+LL | #[derive(ConstParamTy)]
+   |          ^^^^^^^^^^^^
+LL |
+LL | struct Foo2([*mut u8; 1]);
+   |             ------------ this field does not implement `ConstParamTy`
+   |
+note: the `ConstParamTy` impl for `[*mut u8; 1]` requires that `*mut u8: ConstParamTy`
+  --> $DIR/nested_bad_const_param_ty.rs:12:13
+   |
+LL | struct Foo2([*mut u8; 1]);
+   |             ^^^^^^^^^^^^
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
+  --> $DIR/nested_bad_const_param_ty.rs:14:10
+   |
+LL | #[derive(ConstParamTy)]
+   |          ^^^^^^^^^^^^
+LL |
+LL | struct Foo3([fn(); 1]);
+   |             --------- this field does not implement `ConstParamTy`
+   |
+note: the `ConstParamTy` impl for `[fn(); 1]` requires that `fn(): ConstParamTy`
+  --> $DIR/nested_bad_const_param_ty.rs:16:13
+   |
+LL | struct Foo3([fn(); 1]);
+   |             ^^^^^^^^^
+   = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0204`.
diff --git a/tests/ui/const-generics/assoc_const_as_type_argument.rs b/tests/ui/const-generics/assoc_const_as_type_argument.rs
index bec6102417c..ffc7f116a94 100644
--- a/tests/ui/const-generics/assoc_const_as_type_argument.rs
+++ b/tests/ui/const-generics/assoc_const_as_type_argument.rs
@@ -8,7 +8,6 @@ fn foo<T: Trait>() {
     bar::<<T as Trait>::ASSOC>();
     //~^ ERROR: expected associated type, found associated constant `Trait::ASSOC`
     //~| ERROR: unresolved item provided when a constant was expected
-    //~| ERROR type annotations needed
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/assoc_const_as_type_argument.stderr b/tests/ui/const-generics/assoc_const_as_type_argument.stderr
index 53edc19b28c..ac009546135 100644
--- a/tests/ui/const-generics/assoc_const_as_type_argument.stderr
+++ b/tests/ui/const-generics/assoc_const_as_type_argument.stderr
@@ -15,19 +15,7 @@ help: if this generic argument was intended as a const parameter, surround it wi
 LL |     bar::<{ <T as Trait>::ASSOC }>();
    |           +                     +
 
-error[E0284]: type annotations needed
-  --> $DIR/assoc_const_as_type_argument.rs:8:5
-   |
-LL |     bar::<<T as Trait>::ASSOC>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
-   |
-note: required by a const generic parameter in `bar`
-  --> $DIR/assoc_const_as_type_argument.rs:5:8
-   |
-LL | fn bar<const N: usize>() {}
-   |        ^^^^^^^^^^^^^^ required by this const generic parameter in `bar`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0284, E0575, E0747.
-For more information about an error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0575, E0747.
+For more information about an error, try `rustc --explain E0575`.
diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr
index 2ea9d6b35b4..ce7fce25993 100644
--- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr
+++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr
@@ -17,7 +17,7 @@ LL |     let _: [u8; bar::<N>()];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:19:23
+  --> $DIR/const-arg-in-const-arg.rs:18:23
    |
 LL |     let _: [u8; faz::<'a>(&())];
    |                       ^^ cannot perform const operation using `'a`
@@ -26,7 +26,7 @@ LL |     let _: [u8; faz::<'a>(&())];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:21:23
+  --> $DIR/const-arg-in-const-arg.rs:20:23
    |
 LL |     let _: [u8; baz::<'a>(&())];
    |                       ^^ cannot perform const operation using `'a`
@@ -35,7 +35,7 @@ LL |     let _: [u8; baz::<'a>(&())];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:22:23
+  --> $DIR/const-arg-in-const-arg.rs:21:23
    |
 LL |     let _: [u8; faz::<'b>(&())];
    |                       ^^ cannot perform const operation using `'b`
@@ -44,7 +44,7 @@ LL |     let _: [u8; faz::<'b>(&())];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:24:23
+  --> $DIR/const-arg-in-const-arg.rs:23:23
    |
 LL |     let _: [u8; baz::<'b>(&())];
    |                       ^^ cannot perform const operation using `'b`
@@ -53,7 +53,7 @@ LL |     let _: [u8; baz::<'b>(&())];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:27:23
+  --> $DIR/const-arg-in-const-arg.rs:26:23
    |
 LL |     let _ = [0; bar::<N>()];
    |                       ^ cannot perform const operation using `N`
@@ -62,7 +62,7 @@ LL |     let _ = [0; bar::<N>()];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:30:23
+  --> $DIR/const-arg-in-const-arg.rs:28:23
    |
 LL |     let _ = [0; faz::<'a>(&())];
    |                       ^^ cannot perform const operation using `'a`
@@ -71,7 +71,7 @@ LL |     let _ = [0; faz::<'a>(&())];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:32:23
+  --> $DIR/const-arg-in-const-arg.rs:30:23
    |
 LL |     let _ = [0; baz::<'a>(&())];
    |                       ^^ cannot perform const operation using `'a`
@@ -80,7 +80,7 @@ LL |     let _ = [0; baz::<'a>(&())];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:33:23
+  --> $DIR/const-arg-in-const-arg.rs:31:23
    |
 LL |     let _ = [0; faz::<'b>(&())];
    |                       ^^ cannot perform const operation using `'b`
@@ -89,7 +89,7 @@ LL |     let _ = [0; faz::<'b>(&())];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:35:23
+  --> $DIR/const-arg-in-const-arg.rs:33:23
    |
 LL |     let _ = [0; baz::<'b>(&())];
    |                       ^^ cannot perform const operation using `'b`
@@ -98,7 +98,7 @@ LL |     let _ = [0; baz::<'b>(&())];
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:36:24
+  --> $DIR/const-arg-in-const-arg.rs:34:24
    |
 LL |     let _: Foo<{ foo::<T>() }>;
    |                        ^ cannot perform const operation using `T`
@@ -107,7 +107,7 @@ LL |     let _: Foo<{ foo::<T>() }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:37:24
+  --> $DIR/const-arg-in-const-arg.rs:35:24
    |
 LL |     let _: Foo<{ bar::<N>() }>;
    |                        ^ cannot perform const operation using `N`
@@ -116,7 +116,7 @@ LL |     let _: Foo<{ bar::<N>() }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:40:24
+  --> $DIR/const-arg-in-const-arg.rs:37:24
    |
 LL |     let _: Foo<{ faz::<'a>(&()) }>;
    |                        ^^ cannot perform const operation using `'a`
@@ -125,7 +125,7 @@ LL |     let _: Foo<{ faz::<'a>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:42:24
+  --> $DIR/const-arg-in-const-arg.rs:39:24
    |
 LL |     let _: Foo<{ baz::<'a>(&()) }>;
    |                        ^^ cannot perform const operation using `'a`
@@ -134,7 +134,7 @@ LL |     let _: Foo<{ baz::<'a>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:43:24
+  --> $DIR/const-arg-in-const-arg.rs:40:24
    |
 LL |     let _: Foo<{ faz::<'b>(&()) }>;
    |                        ^^ cannot perform const operation using `'b`
@@ -143,7 +143,7 @@ LL |     let _: Foo<{ faz::<'b>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:45:24
+  --> $DIR/const-arg-in-const-arg.rs:42:24
    |
 LL |     let _: Foo<{ baz::<'b>(&()) }>;
    |                        ^^ cannot perform const operation using `'b`
@@ -152,7 +152,7 @@ LL |     let _: Foo<{ baz::<'b>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:46:27
+  --> $DIR/const-arg-in-const-arg.rs:43:27
    |
 LL |     let _ = Foo::<{ foo::<T>() }>;
    |                           ^ cannot perform const operation using `T`
@@ -161,7 +161,7 @@ LL |     let _ = Foo::<{ foo::<T>() }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:47:27
+  --> $DIR/const-arg-in-const-arg.rs:44:27
    |
 LL |     let _ = Foo::<{ bar::<N>() }>;
    |                           ^ cannot perform const operation using `N`
@@ -170,7 +170,7 @@ LL |     let _ = Foo::<{ bar::<N>() }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:50:27
+  --> $DIR/const-arg-in-const-arg.rs:46:27
    |
 LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
    |                           ^^ cannot perform const operation using `'a`
@@ -179,7 +179,7 @@ LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:52:27
+  --> $DIR/const-arg-in-const-arg.rs:48:27
    |
 LL |     let _ = Foo::<{ baz::<'a>(&()) }>;
    |                           ^^ cannot perform const operation using `'a`
@@ -188,7 +188,7 @@ LL |     let _ = Foo::<{ baz::<'a>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:53:27
+  --> $DIR/const-arg-in-const-arg.rs:49:27
    |
 LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
    |                           ^^ cannot perform const operation using `'b`
@@ -197,7 +197,7 @@ LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/const-arg-in-const-arg.rs:55:27
+  --> $DIR/const-arg-in-const-arg.rs:51:27
    |
 LL |     let _ = Foo::<{ baz::<'b>(&()) }>;
    |                           ^^ cannot perform const operation using `'b`
@@ -216,20 +216,8 @@ help: if this generic argument was intended as a const parameter, surround it wi
 LL |     let _: [u8; bar::<{ N }>()];
    |                       +   +
 
-error[E0284]: type annotations needed
-  --> $DIR/const-arg-in-const-arg.rs:16:17
-   |
-LL |     let _: [u8; bar::<N>()];
-   |                 ^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
-   |
-note: required by a const generic parameter in `bar`
-  --> $DIR/const-arg-in-const-arg.rs:9:14
-   |
-LL | const fn bar<const N: usize>() -> usize { N }
-   |              ^^^^^^^^^^^^^^ required by this const generic parameter in `bar`
-
 error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:19:23
+  --> $DIR/const-arg-in-const-arg.rs:18:23
    |
 LL |     let _: [u8; faz::<'a>(&())];
    |                       ^^
@@ -241,7 +229,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:22:23
+  --> $DIR/const-arg-in-const-arg.rs:21:23
    |
 LL |     let _: [u8; faz::<'b>(&())];
    |                       ^^
@@ -253,7 +241,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error[E0747]: unresolved item provided when a constant was expected
-  --> $DIR/const-arg-in-const-arg.rs:37:24
+  --> $DIR/const-arg-in-const-arg.rs:35:24
    |
 LL |     let _: Foo<{ bar::<N>() }>;
    |                        ^
@@ -263,20 +251,8 @@ help: if this generic argument was intended as a const parameter, surround it wi
 LL |     let _: Foo<{ bar::<{ N }>() }>;
    |                        +   +
 
-error[E0284]: type annotations needed
-  --> $DIR/const-arg-in-const-arg.rs:37:18
-   |
-LL |     let _: Foo<{ bar::<N>() }>;
-   |                  ^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
-   |
-note: required by a const generic parameter in `bar`
-  --> $DIR/const-arg-in-const-arg.rs:9:14
-   |
-LL | const fn bar<const N: usize>() -> usize { N }
-   |              ^^^^^^^^^^^^^^ required by this const generic parameter in `bar`
-
 error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:40:24
+  --> $DIR/const-arg-in-const-arg.rs:37:24
    |
 LL |     let _: Foo<{ faz::<'a>(&()) }>;
    |                        ^^
@@ -288,7 +264,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:43:24
+  --> $DIR/const-arg-in-const-arg.rs:40:24
    |
 LL |     let _: Foo<{ faz::<'b>(&()) }>;
    |                        ^^
@@ -300,7 +276,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error: constant expression depends on a generic parameter
-  --> $DIR/const-arg-in-const-arg.rs:26:17
+  --> $DIR/const-arg-in-const-arg.rs:25:17
    |
 LL |     let _ = [0; foo::<T>()];
    |                 ^^^^^^^^^^
@@ -308,7 +284,7 @@ LL |     let _ = [0; foo::<T>()];
    = note: this may fail depending on what value the parameter takes
 
 error[E0747]: unresolved item provided when a constant was expected
-  --> $DIR/const-arg-in-const-arg.rs:27:23
+  --> $DIR/const-arg-in-const-arg.rs:26:23
    |
 LL |     let _ = [0; bar::<N>()];
    |                       ^
@@ -318,20 +294,8 @@ help: if this generic argument was intended as a const parameter, surround it wi
 LL |     let _ = [0; bar::<{ N }>()];
    |                       +   +
 
-error[E0284]: type annotations needed
-  --> $DIR/const-arg-in-const-arg.rs:27:17
-   |
-LL |     let _ = [0; bar::<N>()];
-   |                 ^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
-   |
-note: required by a const generic parameter in `bar`
-  --> $DIR/const-arg-in-const-arg.rs:9:14
-   |
-LL | const fn bar<const N: usize>() -> usize { N }
-   |              ^^^^^^^^^^^^^^ required by this const generic parameter in `bar`
-
 error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:30:23
+  --> $DIR/const-arg-in-const-arg.rs:28:23
    |
 LL |     let _ = [0; faz::<'a>(&())];
    |                       ^^
@@ -343,7 +307,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:33:23
+  --> $DIR/const-arg-in-const-arg.rs:31:23
    |
 LL |     let _ = [0; faz::<'b>(&())];
    |                       ^^
@@ -355,7 +319,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error[E0747]: unresolved item provided when a constant was expected
-  --> $DIR/const-arg-in-const-arg.rs:47:27
+  --> $DIR/const-arg-in-const-arg.rs:44:27
    |
 LL |     let _ = Foo::<{ bar::<N>() }>;
    |                           ^
@@ -365,20 +329,8 @@ help: if this generic argument was intended as a const parameter, surround it wi
 LL |     let _ = Foo::<{ bar::<{ N }>() }>;
    |                           +   +
 
-error[E0284]: type annotations needed
-  --> $DIR/const-arg-in-const-arg.rs:47:21
-   |
-LL |     let _ = Foo::<{ bar::<N>() }>;
-   |                     ^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
-   |
-note: required by a const generic parameter in `bar`
-  --> $DIR/const-arg-in-const-arg.rs:9:14
-   |
-LL | const fn bar<const N: usize>() -> usize { N }
-   |              ^^^^^^^^^^^^^^ required by this const generic parameter in `bar`
-
 error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:50:27
+  --> $DIR/const-arg-in-const-arg.rs:46:27
    |
 LL |     let _ = Foo::<{ faz::<'a>(&()) }>;
    |                           ^^
@@ -390,7 +342,7 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:53:27
+  --> $DIR/const-arg-in-const-arg.rs:49:27
    |
 LL |     let _ = Foo::<{ faz::<'b>(&()) }>;
    |                           ^^
@@ -401,7 +353,7 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: aborting due to 40 previous errors
+error: aborting due to 36 previous errors
 
-Some errors have detailed explanations: E0284, E0747, E0794.
-For more information about an error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0747, E0794.
+For more information about an error, try `rustc --explain E0747`.
diff --git a/tests/ui/const-generics/const-arg-in-const-arg.rs b/tests/ui/const-generics/const-arg-in-const-arg.rs
index b95c63309f7..27b74489fe8 100644
--- a/tests/ui/const-generics/const-arg-in-const-arg.rs
+++ b/tests/ui/const-generics/const-arg-in-const-arg.rs
@@ -15,7 +15,6 @@ fn test<'a, 'b, T, const N: usize>() where &'b (): Sized {
     let _: [u8; foo::<T>()]; //[min]~ ERROR generic parameters may not
     let _: [u8; bar::<N>()]; //[min]~ ERROR generic parameters may not
                              //[min]~^ ERROR unresolved item provided when a constant was expected
-                             //[min]~| ERROR type annotations needed
     let _: [u8; faz::<'a>(&())]; //[min]~ ERROR generic parameters may not
                                  //[min]~^ ERROR cannot specify lifetime arguments
     let _: [u8; baz::<'a>(&())]; //[min]~ ERROR generic parameters may not
@@ -26,7 +25,6 @@ fn test<'a, 'b, T, const N: usize>() where &'b (): Sized {
     let _ = [0; foo::<T>()]; //[min]~ ERROR constant expression depends on a generic parameter
     let _ = [0; bar::<N>()]; //[min]~ ERROR generic parameters may not
                              //[min]~^ ERROR unresolved item provided when a constant was expected
-                             //[min]~| ERROR type annotations needed
     let _ = [0; faz::<'a>(&())]; //[min]~ ERROR generic parameters may not
                                  //[min]~^ ERROR cannot specify lifetime arguments
     let _ = [0; baz::<'a>(&())]; //[min]~ ERROR generic parameters may not
@@ -36,7 +34,6 @@ fn test<'a, 'b, T, const N: usize>() where &'b (): Sized {
     let _: Foo<{ foo::<T>() }>; //[min]~ ERROR generic parameters may not
     let _: Foo<{ bar::<N>() }>; //[min]~ ERROR generic parameters may not
                                 //[min]~^ ERROR unresolved item provided when a constant was expected
-                                //[min]~| ERROR type annotations needed
     let _: Foo<{ faz::<'a>(&()) }>; //[min]~ ERROR generic parameters may not
                                     //[min]~^ ERROR cannot specify lifetime arguments
     let _: Foo<{ baz::<'a>(&()) }>; //[min]~ ERROR generic parameters may not
@@ -46,7 +43,6 @@ fn test<'a, 'b, T, const N: usize>() where &'b (): Sized {
     let _ = Foo::<{ foo::<T>() }>; //[min]~ ERROR generic parameters may not
     let _ = Foo::<{ bar::<N>() }>; //[min]~ ERROR generic parameters may not
                                    //[min]~^ ERROR unresolved item provided when a constant was expected
-                                   //[min]~| ERROR type annotations needed
     let _ = Foo::<{ faz::<'a>(&()) }>; //[min]~ ERROR generic parameters may not
                                        //[min]~^ ERROR cannot specify lifetime arguments
     let _ = Foo::<{ baz::<'a>(&()) }>; //[min]~ ERROR generic parameters may not
diff --git a/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs
new file mode 100644
index 00000000000..5d538d2679d
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.rs
@@ -0,0 +1,14 @@
+#![feature(generic_const_exprs)]
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+#![allow(dead_code)]
+
+#[derive(PartialEq, Eq)]
+struct U;
+
+struct S<const N: U>()
+where
+    S<{ U }>:;
+//~^ ERROR: overflow evaluating the requirement `S<{ U }> well-formed`
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr
new file mode 100644
index 00000000000..b244acb37dd
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/adt_wf_hang.stderr
@@ -0,0 +1,18 @@
+error[E0275]: overflow evaluating the requirement `S<{ U }> well-formed`
+  --> $DIR/adt_wf_hang.rs:11:5
+   |
+LL |     S<{ U }>:;
+   |     ^^^^^^^^
+   |
+note: required by a bound in `S`
+  --> $DIR/adt_wf_hang.rs:11:5
+   |
+LL | struct S<const N: U>()
+   |        - required by a bound in this struct
+LL | where
+LL |     S<{ U }>:;
+   |     ^^^^^^^^ required by this bound in `S`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr
index be79450a3ce..416a9381124 100644
--- a/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.stderr
@@ -20,24 +20,32 @@ error[E0393]: the type parameter `Rhs` must be explicitly specified
   --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27
    |
 LL | ) -> impl Iterator<Item = SubAssign> {
-   |                           ^^^^^^^^^ help: set the type parameter to the desired type: `SubAssign<Rhs>`
+   |                           ^^^^^^^^^
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
    |
    = note: type parameter `Rhs` must be specified for this
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
+help: set the type parameter to the desired type
+   |
+LL | ) -> impl Iterator<Item = SubAssign<Rhs>> {
+   |                                    +++++
 
 error[E0393]: the type parameter `Rhs` must be explicitly specified
   --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:27
    |
 LL | ) -> impl Iterator<Item = SubAssign> {
-   |                           ^^^^^^^^^ help: set the type parameter to the desired type: `SubAssign<Rhs>`
+   |                           ^^^^^^^^^
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
    |
    = note: type parameter `Rhs` must be specified for this
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: set the type parameter to the desired type
+   |
+LL | ) -> impl Iterator<Item = SubAssign<Rhs>> {
+   |                                    +++++
 
 error[E0277]: `()` is not an iterator
   --> $DIR/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs:16:6
diff --git a/tests/ui/const-generics/issues/issue-62878.min.stderr b/tests/ui/const-generics/issues/issue-62878.min.stderr
index 3fd50bbe298..5205726d738 100644
--- a/tests/ui/const-generics/issues/issue-62878.min.stderr
+++ b/tests/ui/const-generics/issues/issue-62878.min.stderr
@@ -30,31 +30,7 @@ help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
 LL + #![feature(generic_arg_infer)]
    |
 
-error[E0284]: type annotations needed
-  --> $DIR/issue-62878.rs:10:5
-   |
-LL |     foo::<_, { [1] }>();
-   |     ^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `foo`
-   |
-note: required by a const generic parameter in `foo`
-  --> $DIR/issue-62878.rs:5:8
-   |
-LL | fn foo<const N: usize, const A: [u8; N]>() {}
-   |        ^^^^^^^^^^^^^^ required by this const generic parameter in `foo`
-
-error[E0284]: type annotations needed
-  --> $DIR/issue-62878.rs:10:5
-   |
-LL |     foo::<_, { [1] }>();
-   |     ^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `A` declared on the function `foo`
-   |
-note: required by a const generic parameter in `foo`
-  --> $DIR/issue-62878.rs:5:24
-   |
-LL | fn foo<const N: usize, const A: [u8; N]>() {}
-   |                        ^^^^^^^^^^^^^^^^ required by this const generic parameter in `foo`
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0284, E0747, E0770.
-For more information about an error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0747, E0770.
+For more information about an error, try `rustc --explain E0747`.
diff --git a/tests/ui/const-generics/issues/issue-62878.rs b/tests/ui/const-generics/issues/issue-62878.rs
index c784e95edd8..0b5269df85e 100644
--- a/tests/ui/const-generics/issues/issue-62878.rs
+++ b/tests/ui/const-generics/issues/issue-62878.rs
@@ -9,6 +9,4 @@ fn foo<const N: usize, const A: [u8; N]>() {}
 fn main() {
     foo::<_, { [1] }>();
     //[min]~^ ERROR: type provided when a constant was expected
-    //[min]~| ERROR type annotations needed
-    //[min]~| ERROR type annotations needed
 }
diff --git a/tests/ui/const-generics/issues/issue-86535-2.rs b/tests/ui/const-generics/issues/issue-86535-2.rs
index 1ba3b6d5347..bd9431dbc85 100644
--- a/tests/ui/const-generics/issues/issue-86535-2.rs
+++ b/tests/ui/const-generics/issues/issue-86535-2.rs
@@ -7,6 +7,7 @@ pub trait Foo {
     fn foo() where [(); Self::ASSOC_C]:;
 }
 
+#[allow(dead_code)]
 struct Bar<const N: &'static ()>;
 impl<const N: &'static ()> Foo for Bar<N> {
     const ASSOC_C: usize = 3;
diff --git a/tests/ui/const-generics/issues/issue-86535.rs b/tests/ui/const-generics/issues/issue-86535.rs
index dd6bc88ad19..cd9934a4a99 100644
--- a/tests/ui/const-generics/issues/issue-86535.rs
+++ b/tests/ui/const-generics/issues/issue-86535.rs
@@ -2,6 +2,7 @@
 #![feature(adt_const_params, generic_const_exprs)]
 #![allow(incomplete_features, unused_variables)]
 
+#[allow(dead_code)]
 struct F<const S: &'static str>;
 impl<const S: &'static str> X for F<{ S }> {
     const W: usize = 3;
diff --git a/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs b/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
index 497c020bde4..e12e07a28e7 100644
--- a/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
+++ b/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
@@ -12,7 +12,6 @@ fn b() {
     //~^ ERROR expected trait, found constant `BAR`
     //~| ERROR expected trait, found constant `BAR`
     //~| ERROR type provided when a constant was expected
-    //~| ERROR type annotations needed
 }
 fn c() {
     foo::<3 + 3>(); //~ ERROR expressions must be enclosed in braces
diff --git a/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr b/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
index c2ba517f609..d9bcc523b1f 100644
--- a/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
+++ b/tests/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
@@ -10,7 +10,7 @@ LL |     foo::<{ BAR + 3 }>();
    |           +         +
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-suggest-missing-braces.rs:18:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:17:11
    |
 LL |     foo::<3 + 3>();
    |           ^^^^^
@@ -21,7 +21,7 @@ LL |     foo::<{ 3 + 3 }>();
    |           +       +
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:21:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:20:15
    |
 LL |     foo::<BAR - 3>();
    |               ^ expected one of `,` or `>`
@@ -32,7 +32,7 @@ LL |     foo::<{ BAR - 3 }>();
    |           +         +
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:24:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:23:15
    |
 LL |     foo::<BAR - BAR>();
    |               ^ expected one of `,` or `>`
@@ -43,7 +43,7 @@ LL |     foo::<{ BAR - BAR }>();
    |           +           +
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-suggest-missing-braces.rs:27:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:26:11
    |
 LL |     foo::<100 - BAR>();
    |           ^^^^^^^^^
@@ -54,7 +54,7 @@ LL |     foo::<{ 100 - BAR }>();
    |           +           +
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:30:19
+  --> $DIR/const-expression-suggest-missing-braces.rs:29:19
    |
 LL |     foo::<bar<i32>()>();
    |                   ^ expected one of `,` or `>`
@@ -65,7 +65,7 @@ LL |     foo::<{ bar<i32>() }>();
    |           +            +
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:33:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:32:21
    |
 LL |     foo::<bar::<i32>()>();
    |                     ^ expected one of `,` or `>`
@@ -76,7 +76,7 @@ LL |     foo::<{ bar::<i32>() }>();
    |           +              +
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:36:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:35:21
    |
 LL |     foo::<bar::<i32>() + BAR>();
    |                     ^ expected one of `,` or `>`
@@ -87,7 +87,7 @@ LL |     foo::<{ bar::<i32>() + BAR }>();
    |           +                    +
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:39:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:38:21
    |
 LL |     foo::<bar::<i32>() - BAR>();
    |                     ^ expected one of `,` or `>`
@@ -98,7 +98,7 @@ LL |     foo::<{ bar::<i32>() - BAR }>();
    |           +                    +
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:42:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:41:15
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |               ^ expected one of `,` or `>`
@@ -109,7 +109,7 @@ LL |     foo::<{ BAR - bar::<i32>() }>();
    |           +                    +
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:45:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:44:15
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |               ^ expected one of `,` or `>`
@@ -137,19 +137,7 @@ error[E0747]: type provided when a constant was expected
 LL |     foo::<BAR + BAR>();
    |           ^^^^^^^^^
 
-error[E0284]: type annotations needed
-  --> $DIR/const-expression-suggest-missing-braces.rs:11:5
-   |
-LL |     foo::<BAR + BAR>();
-   |     ^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the function `foo`
-   |
-note: required by a const generic parameter in `foo`
-  --> $DIR/const-expression-suggest-missing-braces.rs:1:8
-   |
-LL | fn foo<const C: usize>() {}
-   |        ^^^^^^^^^^^^^^ required by this const generic parameter in `foo`
-
-error: aborting due to 15 previous errors
+error: aborting due to 14 previous errors
 
-Some errors have detailed explanations: E0284, E0404, E0747.
-For more information about an error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0404, E0747.
+For more information about an error, try `rustc --explain E0404`.
diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.rs b/tests/ui/const-generics/min_const_generics/macro-fail.rs
index 25726490c2c..8cfa5293cc2 100644
--- a/tests/ui/const-generics/min_const_generics/macro-fail.rs
+++ b/tests/ui/const-generics/min_const_generics/macro-fail.rs
@@ -16,7 +16,6 @@ fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
   //~| ERROR: type provided when a constant was expected
   Example::<gimme_a_const!(marker)>
   //~^ ERROR: type provided when a constant was expected
-  //~| ERROR type annotations needed
 }
 
 fn from_marker(_: impl Marker<{
@@ -37,10 +36,8 @@ fn main() {
 
   let _fail = Example::<external_macro!()>;
   //~^ ERROR: type provided when a constant
-  //~| ERROR type annotations needed
 
   let _fail = Example::<gimme_a_const!()>;
   //~^ ERROR unexpected end of macro invocation
   //~| ERROR: type provided when a constant was expected
-  //~| ERROR type annotations needed
 }
diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.stderr b/tests/ui/const-generics/min_const_generics/macro-fail.stderr
index 4e183fe5b1c..34764982bb0 100644
--- a/tests/ui/const-generics/min_const_generics/macro-fail.stderr
+++ b/tests/ui/const-generics/min_const_generics/macro-fail.stderr
@@ -1,5 +1,5 @@
 error: expected type, found `{`
-  --> $DIR/macro-fail.rs:31:27
+  --> $DIR/macro-fail.rs:30:27
    |
 LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
    |                                 ----------------------
@@ -13,7 +13,7 @@ LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
    = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected type, found `{`
-  --> $DIR/macro-fail.rs:31:27
+  --> $DIR/macro-fail.rs:30:27
    |
 LL |   Example::<gimme_a_const!(marker)>
    |             ----------------------
@@ -41,7 +41,7 @@ LL |   let _fail = Example::<external_macro!()>;
    = note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unexpected end of macro invocation
-  --> $DIR/macro-fail.rs:42:25
+  --> $DIR/macro-fail.rs:40:25
    |
 LL |     macro_rules! gimme_a_const {
    |     -------------------------- when calling this macro
@@ -50,7 +50,7 @@ LL |   let _fail = Example::<gimme_a_const!()>;
    |                         ^^^^^^^^^^^^^^^^ missing tokens in macro arguments
    |
 note: while trying to match meta-variable `$rusty:ident`
-  --> $DIR/macro-fail.rs:31:8
+  --> $DIR/macro-fail.rs:30:8
    |
 LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
    |        ^^^^^^^^^^^^^
@@ -75,63 +75,18 @@ error[E0747]: type provided when a constant was expected
 LL |   Example::<gimme_a_const!(marker)>
    |             ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0284]: type annotations needed
-  --> $DIR/macro-fail.rs:17:3
-   |
-LL |   Example::<gimme_a_const!(marker)>
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the struct `Example`
-   |
-note: required by a const generic parameter in `Example`
-  --> $DIR/macro-fail.rs:1:16
-   |
-LL | struct Example<const N: usize>;
-   |                ^^^^^^^^^^^^^^ required by this const generic parameter in `Example`
-
 error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:38:25
+  --> $DIR/macro-fail.rs:37:25
    |
 LL |   let _fail = Example::<external_macro!()>;
    |                         ^^^^^^^^^^^^^^^^^
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:42:25
+  --> $DIR/macro-fail.rs:40:25
    |
 LL |   let _fail = Example::<gimme_a_const!()>;
    |                         ^^^^^^^^^^^^^^^^
 
-error[E0284]: type annotations needed for `Example<_>`
-  --> $DIR/macro-fail.rs:38:7
-   |
-LL |   let _fail = Example::<external_macro!()>;
-   |       ^^^^^   ---------------------------- type must be known at this point
-   |
-note: required by a const generic parameter in `Example`
-  --> $DIR/macro-fail.rs:1:16
-   |
-LL | struct Example<const N: usize>;
-   |                ^^^^^^^^^^^^^^ required by this const generic parameter in `Example`
-help: consider giving `_fail` an explicit type, where the value of const parameter `N` is specified
-   |
-LL |   let _fail: Example<N> = Example::<external_macro!()>;
-   |            ++++++++++++
-
-error[E0284]: type annotations needed for `Example<_>`
-  --> $DIR/macro-fail.rs:42:7
-   |
-LL |   let _fail = Example::<gimme_a_const!()>;
-   |       ^^^^^   --------------------------- type must be known at this point
-   |
-note: required by a const generic parameter in `Example`
-  --> $DIR/macro-fail.rs:1:16
-   |
-LL | struct Example<const N: usize>;
-   |                ^^^^^^^^^^^^^^ required by this const generic parameter in `Example`
-help: consider giving `_fail` an explicit type, where the value of const parameter `N` is specified
-   |
-LL |   let _fail: Example<N> = Example::<gimme_a_const!()>;
-   |            ++++++++++++
-
-error: aborting due to 12 previous errors
+error: aborting due to 9 previous errors
 
-Some errors have detailed explanations: E0284, E0747.
-For more information about an error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/const-generics/suggest_const_for_array.rs b/tests/ui/const-generics/suggest_const_for_array.rs
index 4d29d069375..b52fd152f97 100644
--- a/tests/ui/const-generics/suggest_const_for_array.rs
+++ b/tests/ui/const-generics/suggest_const_for_array.rs
@@ -5,8 +5,6 @@ fn example<const N: usize>() {}
 fn other() {
     example::<[usize; 3]>();
     //~^ ERROR type provided when a const
-    //~| ERROR type annotations needed
     example::<[usize; 4 + 5]>();
     //~^ ERROR type provided when a const
-    //~| ERROR type annotations needed
 }
diff --git a/tests/ui/const-generics/suggest_const_for_array.stderr b/tests/ui/const-generics/suggest_const_for_array.stderr
index c867914070b..f0ad8368e5d 100644
--- a/tests/ui/const-generics/suggest_const_for_array.stderr
+++ b/tests/ui/const-generics/suggest_const_for_array.stderr
@@ -5,36 +5,11 @@ LL |     example::<[usize; 3]>();
    |               ^^^^^^^^^^ help: array type provided where a `usize` was expected, try: `{ 3 }`
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/suggest_const_for_array.rs:9:15
+  --> $DIR/suggest_const_for_array.rs:8:15
    |
 LL |     example::<[usize; 4 + 5]>();
    |               ^^^^^^^^^^^^^^ help: array type provided where a `usize` was expected, try: `{ 4 + 5 }`
 
-error[E0284]: type annotations needed
-  --> $DIR/suggest_const_for_array.rs:6:5
-   |
-LL |     example::<[usize; 3]>();
-   |     ^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `example`
-   |
-note: required by a const generic parameter in `example`
-  --> $DIR/suggest_const_for_array.rs:3:12
-   |
-LL | fn example<const N: usize>() {}
-   |            ^^^^^^^^^^^^^^ required by this const generic parameter in `example`
-
-error[E0284]: type annotations needed
-  --> $DIR/suggest_const_for_array.rs:9:5
-   |
-LL |     example::<[usize; 4 + 5]>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `example`
-   |
-note: required by a const generic parameter in `example`
-  --> $DIR/suggest_const_for_array.rs:3:12
-   |
-LL | fn example<const N: usize>() {}
-   |            ^^^^^^^^^^^^^^ required by this const generic parameter in `example`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0284, E0747.
-For more information about an error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/consts/const-assert-unchecked-ub.rs b/tests/ui/consts/const-assert-unchecked-ub.rs
index 5c05b813048..ffc02eedcb7 100644
--- a/tests/ui/consts/const-assert-unchecked-ub.rs
+++ b/tests/ui/consts/const-assert-unchecked-ub.rs
@@ -1,10 +1,6 @@
-#![feature(hint_assert_unchecked)]
-#![feature(const_hint_assert_unchecked)]
-
 const _: () = unsafe {
     let n = u32::MAX.count_ones();
     std::hint::assert_unchecked(n < 32); //~ ERROR evaluation of constant value failed
 };
 
-fn main() {
-}
+fn main() {}
diff --git a/tests/ui/consts/const-assert-unchecked-ub.stderr b/tests/ui/consts/const-assert-unchecked-ub.stderr
index 3957a3b1c24..468f15f3472 100644
--- a/tests/ui/consts/const-assert-unchecked-ub.stderr
+++ b/tests/ui/consts/const-assert-unchecked-ub.stderr
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const-assert-unchecked-ub.rs:6:5
+  --> $DIR/const-assert-unchecked-ub.rs:3:5
    |
 LL |     std::hint::assert_unchecked(n < 32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` called with `false`
diff --git a/tests/ui/consts/issue-39974.stderr b/tests/ui/consts/issue-39974.stderr
index 114c4cfeaf7..a371ea5709e 100644
--- a/tests/ui/consts/issue-39974.stderr
+++ b/tests/ui/consts/issue-39974.stderr
@@ -2,10 +2,12 @@ error[E0308]: mismatched types
   --> $DIR/issue-39974.rs:1:21
    |
 LL | const LENGTH: f64 = 2;
-   |                     ^
-   |                     |
-   |                     expected `f64`, found integer
-   |                     help: use a float literal: `2.0`
+   |                     ^ expected `f64`, found integer
+   |
+help: use a float literal
+   |
+LL | const LENGTH: f64 = 2.0;
+   |                      ++
 
 error[E0308]: mismatched types
   --> $DIR/issue-39974.rs:5:19
diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs
index 57767e96596..e71f88b8d5f 100644
--- a/tests/ui/consts/offset_from_ub.rs
+++ b/tests/ui/consts/offset_from_ub.rs
@@ -92,6 +92,14 @@ pub const TOO_FAR_APART2: isize = {
     unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed
     //~| too far before
 };
+pub const TOO_FAR_APART3: isize = {
+    let ptr1 = &0u8 as *const u8;
+    let ptr2 = ptr1.wrapping_offset(isize::MIN);
+    // The result of this would be `isize::MIN`, which *does* fit in an `isize`, but its
+    // absolute value does not. (Also anyway there cannot be an allocation of that size.)
+    unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed
+    //~| too far before
+};
 
 const WRONG_ORDER_UNSIGNED: usize = {
     let a = ['a', 'b', 'c'];
diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr
index 65f75a6e058..7caf6247b9e 100644
--- a/tests/ui/consts/offset_from_ub.stderr
+++ b/tests/ui/consts/offset_from_ub.stderr
@@ -60,13 +60,19 @@ LL |     unsafe { ptr_offset_from(ptr1, ptr2) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:99:14
+  --> $DIR/offset_from_ub.rs:100:14
+   |
+LL |     unsafe { ptr_offset_from(ptr1, ptr2) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:107:14
    |
 LL |     unsafe { ptr_offset_from_unsigned(p, p.add(2) ) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:106:14
+  --> $DIR/offset_from_ub.rs:114:14
    |
 LL |     unsafe { ptr_offset_from_unsigned(ptr2, ptr1) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second
@@ -79,7 +85,7 @@ error[E0080]: evaluation of constant value failed
 note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `OFFSET_VERY_FAR1`
-  --> $DIR/offset_from_ub.rs:115:14
+  --> $DIR/offset_from_ub.rs:123:14
    |
 LL |     unsafe { ptr2.offset_from(ptr1) }
    |              ^^^^^^^^^^^^^^^^^^^^^^
@@ -92,11 +98,11 @@ error[E0080]: evaluation of constant value failed
 note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `OFFSET_VERY_FAR2`
-  --> $DIR/offset_from_ub.rs:121:14
+  --> $DIR/offset_from_ub.rs:129:14
    |
 LL |     unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.rs b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.rs
new file mode 100644
index 00000000000..d821b6a0117
--- /dev/null
+++ b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.rs
@@ -0,0 +1,4 @@
+const FOO: &str = unsafe { &*(1_usize as *const [i64; 0] as *const [u8] as *const str) };
+//~^ ERROR: cannot cast
+
+fn main() {}
diff --git a/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr
new file mode 100644
index 00000000000..3b861d784d8
--- /dev/null
+++ b/tests/ui/consts/slice_elem_ty_mismatch_in_unsizing_cast.stderr
@@ -0,0 +1,9 @@
+error[E0607]: cannot cast thin pointer `*const [i64; 0]` to fat pointer `*const [u8]`
+  --> $DIR/slice_elem_ty_mismatch_in_unsizing_cast.rs:1:31
+   |
+LL | const FOO: &str = unsafe { &*(1_usize as *const [i64; 0] as *const [u8] as *const str) };
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0607`.
diff --git a/tests/ui/deriving/deriving-in-fn.rs b/tests/ui/deriving/deriving-in-fn.rs
index 72da2148350..13f3d39597c 100644
--- a/tests/ui/deriving/deriving-in-fn.rs
+++ b/tests/ui/deriving/deriving-in-fn.rs
@@ -9,5 +9,5 @@ pub fn main() {
     }
 
     let f = Foo { foo: 10 };
-    format!("{:?}", f);
+    let _ = format!("{:?}", f);
 }
diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-smart-pointer-neg.rs
new file mode 100644
index 00000000000..bfb4e86b396
--- /dev/null
+++ b/tests/ui/deriving/deriving-smart-pointer-neg.rs
@@ -0,0 +1,45 @@
+#![feature(derive_smart_pointer, arbitrary_self_types)]
+
+use std::marker::SmartPointer;
+
+#[derive(SmartPointer)]
+//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
+enum NotStruct<'a, T: ?Sized> {
+    Variant(&'a T),
+}
+
+#[derive(SmartPointer)]
+//~^ ERROR: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits
+#[repr(transparent)]
+struct NoPointee<'a, T: ?Sized> {
+    ptr: &'a T,
+}
+
+#[derive(SmartPointer)]
+//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
+#[repr(transparent)]
+struct NoField<'a, #[pointee] T: ?Sized> {}
+//~^ ERROR: lifetime parameter `'a` is never used
+//~| ERROR: type parameter `T` is never used
+
+#[derive(SmartPointer)]
+//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
+#[repr(transparent)]
+struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+//~^ ERROR: lifetime parameter `'a` is never used
+//~| ERROR: type parameter `T` is never used
+
+#[derive(SmartPointer)]
+//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
+struct NotTransparent<'a, #[pointee] T: ?Sized> {
+    ptr: &'a T,
+}
+
+// However, reordering attributes should work nevertheless.
+#[repr(transparent)]
+#[derive(SmartPointer)]
+struct ThisIsAPossibleSmartPointer<'a, #[pointee] T: ?Sized> {
+    ptr: &'a T,
+}
+
+fn main() {}
diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr
new file mode 100644
index 00000000000..d994a6ee376
--- /dev/null
+++ b/tests/ui/deriving/deriving-smart-pointer-neg.stderr
@@ -0,0 +1,75 @@
+error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
+  --> $DIR/deriving-smart-pointer-neg.rs:5:10
+   |
+LL | #[derive(SmartPointer)]
+   |          ^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits
+  --> $DIR/deriving-smart-pointer-neg.rs:11:10
+   |
+LL | #[derive(SmartPointer)]
+   |          ^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `SmartPointer` can only be derived on `struct`s with at least one field
+  --> $DIR/deriving-smart-pointer-neg.rs:18:10
+   |
+LL | #[derive(SmartPointer)]
+   |          ^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `SmartPointer` can only be derived on `struct`s with at least one field
+  --> $DIR/deriving-smart-pointer-neg.rs:25:10
+   |
+LL | #[derive(SmartPointer)]
+   |          ^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
+  --> $DIR/deriving-smart-pointer-neg.rs:32:10
+   |
+LL | #[derive(SmartPointer)]
+   |          ^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0392]: lifetime parameter `'a` is never used
+  --> $DIR/deriving-smart-pointer-neg.rs:21:16
+   |
+LL | struct NoField<'a, #[pointee] T: ?Sized> {}
+   |                ^^ unused lifetime parameter
+   |
+   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/deriving-smart-pointer-neg.rs:21:31
+   |
+LL | struct NoField<'a, #[pointee] T: ?Sized> {}
+   |                               ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: lifetime parameter `'a` is never used
+  --> $DIR/deriving-smart-pointer-neg.rs:28:20
+   |
+LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+   |                    ^^ unused lifetime parameter
+   |
+   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/deriving-smart-pointer-neg.rs:28:35
+   |
+LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+   |                                   ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/deriving/deriving-smart-pointer.rs b/tests/ui/deriving/deriving-smart-pointer.rs
index cfc3369850b..d34a502da68 100644
--- a/tests/ui/deriving/deriving-smart-pointer.rs
+++ b/tests/ui/deriving/deriving-smart-pointer.rs
@@ -4,6 +4,7 @@
 use std::marker::SmartPointer;
 
 #[derive(SmartPointer)]
+#[repr(transparent)]
 struct MyPointer<'a, #[pointee] T: ?Sized> {
     ptr: &'a T,
 }
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 d189d2dbded..a686b913c55 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
@@ -29,7 +29,10 @@ error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Tex
   --> $DIR/as_expression.rs:57:5
    |
 LL |     SelectInt.check("bar");
-   |     ^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     ^^^^^^^^^^^^^^^^^^^^^^ expected `Integer`, found `Text`
+   |
+   = note: expected struct `Integer`
+              found struct `Text`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/did_you_mean/issue-34337.stderr b/tests/ui/did_you_mean/issue-34337.stderr
index c727a565dbe..7bb651c47d0 100644
--- a/tests/ui/did_you_mean/issue-34337.stderr
+++ b/tests/ui/did_you_mean/issue-34337.stderr
@@ -2,10 +2,13 @@ error[E0596]: cannot borrow `key` as mutable, as it is not declared as mutable
   --> $DIR/issue-34337.rs:6:9
    |
 LL |     get(&mut key);
-   |         ^^^^^^^^
-   |         |
-   |         cannot borrow as mutable
-   |         help: try removing `&mut` here
+   |         ^^^^^^^^ cannot borrow as mutable
+   |
+help: try removing `&mut` here
+   |
+LL -     get(&mut key);
+LL +     get(key);
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/did_you_mean/issue-37139.stderr b/tests/ui/did_you_mean/issue-37139.stderr
index a07d83b31db..dbaab70d8bc 100644
--- a/tests/ui/did_you_mean/issue-37139.stderr
+++ b/tests/ui/did_you_mean/issue-37139.stderr
@@ -2,10 +2,13 @@ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/issue-37139.rs:12:18
    |
 LL |             test(&mut x);
-   |                  ^^^^^^
-   |                  |
-   |                  cannot borrow as mutable
-   |                  help: try removing `&mut` here
+   |                  ^^^^^^ cannot borrow as mutable
+   |
+help: try removing `&mut` here
+   |
+LL -             test(&mut x);
+LL +             test(x);
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/did_you_mean/issue-53280-expected-float-found-integer-literal.stderr b/tests/ui/did_you_mean/issue-53280-expected-float-found-integer-literal.stderr
index 6f853ccab37..6e32483aee4 100644
--- a/tests/ui/did_you_mean/issue-53280-expected-float-found-integer-literal.stderr
+++ b/tests/ui/did_you_mean/issue-53280-expected-float-found-integer-literal.stderr
@@ -2,31 +2,40 @@ error[E0308]: mismatched types
   --> $DIR/issue-53280-expected-float-found-integer-literal.rs:2:24
    |
 LL |     let sixteen: f32 = 16;
-   |                  ---   ^^
-   |                  |     |
-   |                  |     expected `f32`, found integer
-   |                  |     help: use a float literal: `16.0`
+   |                  ---   ^^ expected `f32`, found integer
+   |                  |
    |                  expected due to this
+   |
+help: use a float literal
+   |
+LL |     let sixteen: f32 = 16.0;
+   |                          ++
 
 error[E0308]: mismatched types
   --> $DIR/issue-53280-expected-float-found-integer-literal.rs:5:38
    |
 LL |     let a_million_and_seventy: f64 = 1_000_070;
-   |                                ---   ^^^^^^^^^
-   |                                |     |
-   |                                |     expected `f64`, found integer
-   |                                |     help: use a float literal: `1_000_070.0`
+   |                                ---   ^^^^^^^^^ expected `f64`, found integer
+   |                                |
    |                                expected due to this
+   |
+help: use a float literal
+   |
+LL |     let a_million_and_seventy: f64 = 1_000_070.0;
+   |                                               ++
 
 error[E0308]: mismatched types
   --> $DIR/issue-53280-expected-float-found-integer-literal.rs:8:30
    |
 LL |     let negative_nine: f32 = -9;
-   |                        ---   ^^
-   |                        |     |
-   |                        |     expected `f32`, found integer
-   |                        |     help: use a float literal: `-9.0`
+   |                        ---   ^^ expected `f32`, found integer
+   |                        |
    |                        expected due to this
+   |
+help: use a float literal
+   |
+LL |     let negative_nine: f32 = -9.0;
+   |                                ++
 
 error[E0308]: mismatched types
   --> $DIR/issue-53280-expected-float-found-integer-literal.rs:15:30
diff --git a/tests/ui/error-codes/E0057.stderr b/tests/ui/error-codes/E0057.stderr
index 9b0cf069824..efd2af6d609 100644
--- a/tests/ui/error-codes/E0057.stderr
+++ b/tests/ui/error-codes/E0057.stderr
@@ -18,16 +18,18 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/E0057.rs:5:13
    |
 LL |     let c = f(2, 3);
-   |             ^  ---
-   |                | |
-   |                | unexpected argument of type `{integer}`
-   |                help: remove the extra argument
+   |             ^    - unexpected argument of type `{integer}`
    |
 note: closure defined here
   --> $DIR/E0057.rs:2:13
    |
 LL |     let f = |x| x * 3;
    |             ^^^
+help: remove the extra argument
+   |
+LL -     let c = f(2, 3);
+LL +     let c = f(2);
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/error-codes/E0308.stderr b/tests/ui/error-codes/E0308.stderr
index bc6c5a632a1..709b3119276 100644
--- a/tests/ui/error-codes/E0308.stderr
+++ b/tests/ui/error-codes/E0308.stderr
@@ -5,7 +5,7 @@ LL |     fn size_of<T>();
    |                    ^ expected `usize`, found `()`
    |
    = note: expected signature `extern "rust-intrinsic" fn() -> usize`
-              found signature `extern "rust-intrinsic" fn()`
+              found signature `extern "rust-intrinsic" fn() -> ()`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0393.stderr b/tests/ui/error-codes/E0393.stderr
index 4083fa23e87..489398b7be5 100644
--- a/tests/ui/error-codes/E0393.stderr
+++ b/tests/ui/error-codes/E0393.stderr
@@ -5,9 +5,13 @@ LL | trait A<T=Self> {}
    | --------------- type parameter `T` must be specified for this
 LL |
 LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {}
-   |                                               ^ help: set the type parameter to the desired type: `A<T>`
+   |                                               ^
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
+help: set the type parameter to the desired type
+   |
+LL | fn together_we_will_rule_the_galaxy(son: &dyn A<T>) {}
+   |                                                +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/explicit-tail-calls/constck.rs b/tests/ui/explicit-tail-calls/constck.rs
new file mode 100644
index 00000000000..938f15f12c0
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/constck.rs
@@ -0,0 +1,22 @@
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+const fn f() {
+    if false {
+        become not_const();
+        //~^ error: cannot call non-const fn `not_const` in constant functions
+    }
+}
+
+const fn g((): ()) {
+    if false {
+        become yes_const(not_const());
+        //~^ error: cannot call non-const fn `not_const` in constant functions
+    }
+}
+
+fn not_const() {}
+
+const fn yes_const((): ()) {}
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/constck.stderr b/tests/ui/explicit-tail-calls/constck.stderr
new file mode 100644
index 00000000000..d9967c45fa0
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/constck.stderr
@@ -0,0 +1,19 @@
+error[E0015]: cannot call non-const fn `not_const` in constant functions
+  --> $DIR/constck.rs:6:16
+   |
+LL |         become not_const();
+   |                ^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `not_const` in constant functions
+  --> $DIR/constck.rs:13:26
+   |
+LL |         become yes_const(not_const());
+   |                          ^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.rs b/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.rs
new file mode 100644
index 00000000000..5a105ee4eb5
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.rs
@@ -0,0 +1,14 @@
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+pub const fn test(_: &Type) {
+    const fn takes_borrow(_: &Type) {}
+
+    let local = Type;
+    become takes_borrow(&local);
+    //~^ error: `local` does not live long enough
+}
+
+struct Type;
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr b/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr
new file mode 100644
index 00000000000..75fb13c378c
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `local` does not live long enough
+  --> $DIR/ctfe-arg-bad-borrow.rs:8:25
+   |
+LL |     let local = Type;
+   |         ----- binding `local` declared here
+LL |     become takes_borrow(&local);
+   |                         ^^^^^^ borrowed value does not live long enough
+LL |
+LL | }
+   | - `local` dropped here while still borrowed
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs b/tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs
new file mode 100644
index 00000000000..50bf6c946ca
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs
@@ -0,0 +1,13 @@
+//@ check-pass
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+pub const fn test(x: &Type) {
+    const fn takes_borrow(_: &Type) {}
+
+    become takes_borrow(x);
+}
+
+pub struct Type;
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/ctfe-arg-move.rs b/tests/ui/explicit-tail-calls/ctfe-arg-move.rs
new file mode 100644
index 00000000000..88ff3a4a5ad
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ctfe-arg-move.rs
@@ -0,0 +1,15 @@
+//@ check-pass
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+pub const fn test(s: String) -> String {
+    const fn takes_string(s: String) -> String {
+        s
+    }
+
+    become takes_string(s);
+}
+
+struct Type;
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs b/tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs
new file mode 100644
index 00000000000..86041b66960
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs
@@ -0,0 +1,43 @@
+//@ run-pass
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+/// A very unnecessarily complicated "implementation" of the Collatz conjecture.
+/// Returns the number of steps to reach `1`.
+///
+/// This is just a test for tail calls, which involves multiple functions calling each other.
+///
+/// Panics if `x == 0`.
+const fn collatz(x: u32) -> u32 {
+    assert!(x > 0);
+
+    const fn switch(x: u32, steps: u32) -> u32 {
+        match x {
+            1 => steps,
+            _ if x & 1 == 0 => become div2(x, steps + 1),
+            _ => become mul3plus1(x, steps + 1),
+        }
+    }
+
+    const fn div2(x: u32, steps: u32) -> u32 {
+        become switch(x >> 1, steps)
+    }
+
+    const fn mul3plus1(x: u32, steps: u32) -> u32 {
+        become switch(3 * x + 1, steps)
+    }
+
+    switch(x, 0)
+}
+
+const ASSERTS: () = {
+    assert!(collatz(1) == 0);
+    assert!(collatz(2) == 1);
+    assert!(collatz(3) == 7);
+    assert!(collatz(4) == 2);
+    assert!(collatz(6171) == 261);
+};
+
+fn main() {
+    let _ = ASSERTS;
+}
diff --git a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr
new file mode 100644
index 00000000000..4a1e50b4111
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.return.stderr
@@ -0,0 +1,36 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-id-unlimited.rs:17:42
+   |
+LL |             #[cfg(r#return)] _ => return inner(acc + 1, n - 1),
+   |                                          ^^^^^^^^^^^^^^^^^^^^^ reached the configured maximum number of stack frames
+   |
+note: inside `inner`
+  --> $DIR/ctfe-id-unlimited.rs:17:42
+   |
+LL |             #[cfg(r#return)] _ => return inner(acc + 1, n - 1),
+   |                                          ^^^^^^^^^^^^^^^^^^^^^
+note: [... 125 additional calls inside `inner` ...]
+  --> $DIR/ctfe-id-unlimited.rs:17:42
+   |
+LL |             #[cfg(r#return)] _ => return inner(acc + 1, n - 1),
+   |                                          ^^^^^^^^^^^^^^^^^^^^^
+note: inside `rec_id`
+  --> $DIR/ctfe-id-unlimited.rs:22:5
+   |
+LL |     inner(0, n)
+   |     ^^^^^^^^^^^
+note: inside `ID_ED`
+  --> $DIR/ctfe-id-unlimited.rs:29:20
+   |
+LL | const ID_ED: u32 = rec_id(ORIGINAL);
+   |                    ^^^^^^^^^^^^^^^^
+
+note: erroneous constant encountered
+  --> $DIR/ctfe-id-unlimited.rs:31:40
+   |
+LL | const ASSERT: () = assert!(ORIGINAL == ID_ED);
+   |                                        ^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs
new file mode 100644
index 00000000000..54e68b2b7f7
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs
@@ -0,0 +1,35 @@
+//@ revisions: become return
+//@ [become] run-pass
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+// This is an identity function (`|x| x`), but implemented using recursion.
+// Each step we increment accumulator and decrement the number.
+//
+// With normal calls this fails compilation because of the recursion limit,
+// but with tail calls/`become` we don't grow the stack/spend recursion limit
+// so this should compile.
+const fn rec_id(n: u32) -> u32 {
+    const fn inner(acc: u32, n: u32) -> u32 {
+        match n {
+            0 => acc,
+            #[cfg(r#become)] _ => become inner(acc + 1, n - 1),
+            #[cfg(r#return)] _ => return inner(acc + 1, n - 1),
+            //[return]~^ error: evaluation of constant value failed
+        }
+    }
+
+    inner(0, n)
+}
+
+// Some relatively big number that is higher than recursion limit
+const ORIGINAL: u32 = 12345;
+// Original number, but with identity function applied
+// (this is the same, but requires execution of the recursion)
+const ID_ED: u32 = rec_id(ORIGINAL);
+// Assert to make absolutely sure the computation actually happens
+const ASSERT: () = assert!(ORIGINAL == ID_ED);
+
+fn main() {
+    let _ = ASSERT;
+}
diff --git a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs
new file mode 100644
index 00000000000..3d69cde2989
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs
@@ -0,0 +1,19 @@
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+pub const fn f() {
+    become g();
+}
+
+const fn g() {
+    panic!()
+    //~^ error: evaluation of constant value failed
+    //~| note: in this expansion of panic!
+    //~| note: inside `g`
+    //~| note: in this expansion of panic!
+}
+
+const _: () = f();
+//~^ note: inside `_`
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr
new file mode 100644
index 00000000000..8c070512105
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.stderr
@@ -0,0 +1,21 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ctfe-tail-call-panic.rs:9:5
+   |
+LL |     panic!()
+   |     ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/ctfe-tail-call-panic.rs:9:5
+   |
+note: inside `g`
+  --> $DIR/ctfe-tail-call-panic.rs:9:5
+   |
+LL |     panic!()
+   |     ^^^^^^^^
+note: inside `_`
+  --> $DIR/ctfe-tail-call-panic.rs:16:15
+   |
+LL | const _: () = f();
+   |               ^^^
+   = 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/explicit-tail-calls/drop-order.rs b/tests/ui/explicit-tail-calls/drop-order.rs
new file mode 100644
index 00000000000..e20730446ec
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/drop-order.rs
@@ -0,0 +1,70 @@
+// FIXME(explicit_tail_calls): enable this test once rustc_codegen_ssa supports tail calls
+//@ ignore-test: tail calls are not implemented in rustc_codegen_ssa yet, so this causes 🧊
+//@ run-pass
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+use std::cell::RefCell;
+
+fn main() {
+    let tail_counter = Default::default();
+    tail_recursive(0, &tail_counter);
+    assert_eq!(tail_counter.into_inner(), (0..128).collect::<Vec<u8>>());
+
+    let simply_counter = Default::default();
+    simply_recursive(0, &simply_counter);
+    assert_eq!(simply_counter.into_inner(), (0..128).rev().collect::<Vec<u8>>());
+
+    let scope_counter = Default::default();
+    out_of_inner_scope(&scope_counter);
+    assert_eq!(scope_counter.into_inner(), (0..8).collect::<Vec<u8>>());
+}
+
+fn tail_recursive(n: u8, order: &RefCell<Vec<u8>>) {
+    if n >= 128 {
+        return;
+    }
+
+    let _local = DropCounter(n, order);
+
+    become tail_recursive(n + 1, order)
+}
+
+fn simply_recursive(n: u8, order: &RefCell<Vec<u8>>) {
+    if n >= 128 {
+        return;
+    }
+
+    let _local = DropCounter(n, order);
+
+    return simply_recursive(n + 1, order);
+}
+
+fn out_of_inner_scope(order: &RefCell<Vec<u8>>) {
+    fn inner(order: &RefCell<Vec<u8>>) {
+        let _7 = DropCounter(7, order);
+        let _6 = DropCounter(6, order);
+    }
+
+    let _5 = DropCounter(5, order);
+    let _4 = DropCounter(4, order);
+
+    if true {
+        let _3 = DropCounter(3, order);
+        let _2 = DropCounter(2, order);
+        loop {
+            let _1 = DropCounter(1, order);
+            let _0 = DropCounter(0, order);
+
+            become inner(order);
+        }
+    }
+}
+
+struct DropCounter<'a>(u8, &'a RefCell<Vec<u8>>);
+
+impl Drop for DropCounter<'_> {
+    #[track_caller]
+    fn drop(&mut self) {
+        self.1.borrow_mut().push(self.0);
+    }
+}
diff --git a/tests/ui/explicit-tail-calls/return-mismatches.rs b/tests/ui/explicit-tail-calls/return-mismatches.rs
index 8094a192913..935a1a1d28b 100644
--- a/tests/ui/explicit-tail-calls/return-mismatches.rs
+++ b/tests/ui/explicit-tail-calls/return-mismatches.rs
@@ -13,7 +13,7 @@ fn _f1() {
     become _g1(); //~ error: mismatched types
 }
 
-fn _g1() -> ! { //~ WARN: cannot return without recursing
+fn _g1() -> ! {
     become _g1();
 }
 
diff --git a/tests/ui/explicit-tail-calls/return-mismatches.stderr b/tests/ui/explicit-tail-calls/return-mismatches.stderr
index 31c7a46ded9..1dcc35797c1 100644
--- a/tests/ui/explicit-tail-calls/return-mismatches.stderr
+++ b/tests/ui/explicit-tail-calls/return-mismatches.stderr
@@ -22,17 +22,6 @@ error[E0308]: mismatched types
 LL |     become _g2();
    |     ^^^^^^^^^^^^ expected `u32`, found `u16`
 
-warning: function cannot return without recursing
-  --> $DIR/return-mismatches.rs:16:1
-   |
-LL | fn _g1() -> ! {
-   | ^^^^^^^^^^^^^ cannot return without recursing
-LL |     become _g1();
-   |            ----- recursive call site
-   |
-   = help: a `loop` may express intention better if this is on purpose
-   = note: `#[warn(unconditional_recursion)]` on by default
-
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/explicit-tail-calls/unsafeck.rs b/tests/ui/explicit-tail-calls/unsafeck.rs
new file mode 100644
index 00000000000..872a70ca3a0
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/unsafeck.rs
@@ -0,0 +1,11 @@
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+const fn f() {
+    become dangerous();
+    //~^ error: call to unsafe function `dangerous` is unsafe and requires unsafe function or block
+}
+
+const unsafe fn dangerous() {}
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/unsafeck.stderr b/tests/ui/explicit-tail-calls/unsafeck.stderr
new file mode 100644
index 00000000000..25b8967e17b
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/unsafeck.stderr
@@ -0,0 +1,11 @@
+error[E0133]: call to unsafe function `dangerous` is unsafe and requires unsafe function or block
+  --> $DIR/unsafeck.rs:5:12
+   |
+LL |     become dangerous();
+   |            ^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
index ae8005592cd..3257a9ca624 100644
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
+++ b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
@@ -1,6 +1,7 @@
 use std::marker::SmartPointer; //~ ERROR use of unstable library feature 'derive_smart_pointer'
 
 #[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer'
+#[repr(transparent)]
 struct MyPointer<'a, #[pointee] T: ?Sized> {
     //~^ ERROR the `#[pointee]` attribute is an experimental feature
     ptr: &'a T,
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
index 0ffd82fb9e1..19501939dc5 100644
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
+++ b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
@@ -9,7 +9,7 @@ LL | #[derive(SmartPointer)]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the `#[pointee]` attribute is an experimental feature
-  --> $DIR/feature-gate-derive-smart-pointer.rs:4:22
+  --> $DIR/feature-gate-derive-smart-pointer.rs:5:22
    |
 LL | struct MyPointer<'a, #[pointee] T: ?Sized> {
    |                      ^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr b/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr
index d1f4ed5cb04..696326157ce 100644
--- a/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr
+++ b/tests/ui/feature-gates/feature-gate-negate-unsigned.stderr
@@ -2,12 +2,13 @@ error[E0600]: cannot apply unary operator `-` to type `usize`
   --> $DIR/feature-gate-negate-unsigned.rs:10:23
    |
 LL |     let _max: usize = -1;
-   |                       ^^
-   |                       |
-   |                       cannot apply unary operator `-`
-   |                       help: you may have meant the maximum value of `usize`: `usize::MAX`
+   |                       ^^ cannot apply unary operator `-`
    |
    = note: unsigned values cannot be negated
+help: you may have meant the maximum value of `usize`
+   |
+LL |     let _max: usize = usize::MAX;
+   |                       ~~~~~~~~~~
 
 error[E0600]: cannot apply unary operator `-` to type `u8`
   --> $DIR/feature-gate-negate-unsigned.rs:14:14
diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr
index 41bd66b13e7..18f46928fab 100644
--- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr
+++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr
@@ -1,33 +1,13 @@
 error[E0658]: return type notation is experimental
-  --> $DIR/feature-gate-return_type_notation.rs:14:17
+  --> $DIR/feature-gate-return_type_notation.rs:10:18
    |
-LL | fn foo<T: Trait<m(): Send>>() {}
-   |                 ^^^^^^^^^
+LL | fn foo<T: Trait<m(..): Send>>() {}
+   |                  ^^^^
    |
    = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
    = help: add `#![feature(return_type_notation)]` 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: parenthesized generic arguments cannot be used in associated type constraints
-  --> $DIR/feature-gate-return_type_notation.rs:14:17
-   |
-LL | fn foo<T: Trait<m(): Send>>() {}
-   |                 ^--
-   |                  |
-   |                  help: remove these parentheses
-
-error: expected type, found function
-  --> $DIR/feature-gate-return_type_notation.rs:14:17
-   |
-LL | fn foo<T: Trait<m(): Send>>() {}
-   |                 ^ unexpected function
-   |
-note: the associated function is defined here
-  --> $DIR/feature-gate-return_type_notation.rs:10:5
-   |
-LL |     async fn m();
-   |     ^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr
index 79c626cef35..18f46928fab 100644
--- a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr
+++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr
@@ -1,14 +1,13 @@
-warning: return type notation is experimental
-  --> $DIR/feature-gate-return_type_notation.rs:14:17
+error[E0658]: return type notation is experimental
+  --> $DIR/feature-gate-return_type_notation.rs:10:18
    |
-LL | fn foo<T: Trait<m(): Send>>() {}
-   |                 ^^^^^^^^^
+LL | fn foo<T: Trait<m(..): Send>>() {}
+   |                  ^^^^
    |
    = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
    = help: add `#![feature(return_type_notation)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
 
-warning: 1 warning emitted
+error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.rs b/tests/ui/feature-gates/feature-gate-return_type_notation.rs
index 7ae6cd0234b..254b794e431 100644
--- a/tests/ui/feature-gates/feature-gate-return_type_notation.rs
+++ b/tests/ui/feature-gates/feature-gate-return_type_notation.rs
@@ -1,21 +1,13 @@
 //@ edition: 2021
 //@ revisions: cfg no
 
-//@ [no] check-pass
-// Since we're not adding new syntax, `cfg`'d out RTN must pass.
-
-
 trait Trait {
     #[allow(async_fn_in_trait)]
     async fn m();
 }
 
 #[cfg(cfg)]
-fn foo<T: Trait<m(): Send>>() {}
-//[cfg]~^ ERROR return type notation is experimental
-//[cfg]~| ERROR parenthesized generic arguments cannot be used in associated type constraints
-//[cfg]~| ERROR expected type, found function
-//[no]~^^^^ WARN return type notation is experimental
-//[no]~| WARN unstable syntax can change at any point in the future, causing a hard error!
+fn foo<T: Trait<m(..): Send>>() {}
+//~^ ERROR return type notation is experimental
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
index 1b9febd431d..584724dfe59 100644
--- a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
+++ b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
@@ -89,13 +89,14 @@ error[E0053]: method `call` has an incompatible type for trait
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:13:32
    |
 LL |     extern "rust-call" fn call(self, args: ()) -> () {}
-   |                                ^^^^
-   |                                |
-   |                                expected `&Foo`, found `Foo`
-   |                                help: change the self-receiver type to match the trait: `&self`
+   |                                ^^^^ expected `&Foo`, found `Foo`
    |
    = note: expected signature `extern "rust-call" fn(&Foo, ()) -> _`
-              found signature `extern "rust-call" fn(Foo, ())`
+              found signature `extern "rust-call" fn(Foo, ()) -> ()`
+help: change the self-receiver type to match the trait
+   |
+LL |     extern "rust-call" fn call(&self, args: ()) -> () {}
+   |                                ~~~~~
 
 error[E0183]: manual implementations of `FnOnce` are experimental
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:18:6
@@ -158,13 +159,14 @@ error[E0053]: method `call_mut` has an incompatible type for trait
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:36
    |
 LL |     extern "rust-call" fn call_mut(&self, args: ()) -> () {}
-   |                                    ^^^^^
-   |                                    |
-   |                                    types differ in mutability
-   |                                    help: change the self-receiver type to match the trait: `&mut self`
+   |                                    ^^^^^ types differ in mutability
    |
    = note: expected signature `extern "rust-call" fn(&mut Bar, ()) -> _`
-              found signature `extern "rust-call" fn(&Bar, ())`
+              found signature `extern "rust-call" fn(&Bar, ()) -> ()`
+help: change the self-receiver type to match the trait
+   |
+LL |     extern "rust-call" fn call_mut(&mut self, args: ()) -> () {}
+   |                                    ~~~~~~~~~
 
 error[E0046]: not all trait items implemented, missing: `Output`
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:35:1
diff --git a/tests/ui/fmt/struct-field-as-captured-argument.fixed b/tests/ui/fmt/struct-field-as-captured-argument.fixed
index e13af744ec8..0da40737354 100644
--- a/tests/ui/fmt/struct-field-as-captured-argument.fixed
+++ b/tests/ui/fmt/struct-field-as-captured-argument.fixed
@@ -8,11 +8,11 @@ struct Foo {
 fn main() {
     let foo = Foo { field: 0 };
     let bar = 3;
-    format!("{0}", foo.field); //~ ERROR invalid format string: field access isn't supported
-    format!("{1} {} {bar}", "aa", foo.field); //~ ERROR invalid format string: field access isn't supported
-    format!("{2} {} {1} {bar}", "aa", "bb", foo.field); //~ ERROR invalid format string: field access isn't supported
-    format!("{1} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
-    format!("{1:?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
-    format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
-    format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{0}", foo.field); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{1} {} {bar}", "aa", foo.field); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{2} {} {1} {bar}", "aa", "bb", foo.field); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{1} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{1:?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
 }
diff --git a/tests/ui/fmt/struct-field-as-captured-argument.rs b/tests/ui/fmt/struct-field-as-captured-argument.rs
index 6a875a85848..325b4e3a218 100644
--- a/tests/ui/fmt/struct-field-as-captured-argument.rs
+++ b/tests/ui/fmt/struct-field-as-captured-argument.rs
@@ -8,11 +8,11 @@ struct Foo {
 fn main() {
     let foo = Foo { field: 0 };
     let bar = 3;
-    format!("{foo.field}"); //~ ERROR invalid format string: field access isn't supported
-    format!("{foo.field} {} {bar}", "aa"); //~ ERROR invalid format string: field access isn't supported
-    format!("{foo.field} {} {1} {bar}", "aa", "bb"); //~ ERROR invalid format string: field access isn't supported
-    format!("{foo.field} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
-    format!("{foo.field:?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
-    format!("{foo.field:#?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
-    format!("{foo.field:.3} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{foo.field}"); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{foo.field} {} {bar}", "aa"); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{foo.field} {} {1} {bar}", "aa", "bb"); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{foo.field} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{foo.field:?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{foo.field:#?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    let _ = format!("{foo.field:.3} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
 }
diff --git a/tests/ui/fmt/struct-field-as-captured-argument.stderr b/tests/ui/fmt/struct-field-as-captured-argument.stderr
index 7ea8b4068f2..4ef022cecb0 100644
--- a/tests/ui/fmt/struct-field-as-captured-argument.stderr
+++ b/tests/ui/fmt/struct-field-as-captured-argument.stderr
@@ -1,79 +1,79 @@
 error: invalid format string: field access isn't supported
-  --> $DIR/struct-field-as-captured-argument.rs:11:15
+  --> $DIR/struct-field-as-captured-argument.rs:11:23
    |
-LL |     format!("{foo.field}");
-   |               ^^^^^^^^^ not supported in format string
+LL |     let _ = format!("{foo.field}");
+   |                       ^^^^^^^^^ not supported in format string
    |
 help: consider using a positional formatting argument instead
    |
-LL |     format!("{0}", foo.field);
-   |               ~  +++++++++++
+LL |     let _ = format!("{0}", foo.field);
+   |                       ~  +++++++++++
 
 error: invalid format string: field access isn't supported
-  --> $DIR/struct-field-as-captured-argument.rs:12:15
+  --> $DIR/struct-field-as-captured-argument.rs:12:23
    |
-LL |     format!("{foo.field} {} {bar}", "aa");
-   |               ^^^^^^^^^ not supported in format string
+LL |     let _ = format!("{foo.field} {} {bar}", "aa");
+   |                       ^^^^^^^^^ not supported in format string
    |
 help: consider using a positional formatting argument instead
    |
-LL |     format!("{1} {} {bar}", "aa", foo.field);
-   |               ~                 +++++++++++
+LL |     let _ = format!("{1} {} {bar}", "aa", foo.field);
+   |                       ~                 +++++++++++
 
 error: invalid format string: field access isn't supported
-  --> $DIR/struct-field-as-captured-argument.rs:13:15
+  --> $DIR/struct-field-as-captured-argument.rs:13:23
    |
-LL |     format!("{foo.field} {} {1} {bar}", "aa", "bb");
-   |               ^^^^^^^^^ not supported in format string
+LL |     let _ = format!("{foo.field} {} {1} {bar}", "aa", "bb");
+   |                       ^^^^^^^^^ not supported in format string
    |
 help: consider using a positional formatting argument instead
    |
-LL |     format!("{2} {} {1} {bar}", "aa", "bb", foo.field);
-   |               ~                           +++++++++++
+LL |     let _ = format!("{2} {} {1} {bar}", "aa", "bb", foo.field);
+   |                       ~                           +++++++++++
 
 error: invalid format string: field access isn't supported
-  --> $DIR/struct-field-as-captured-argument.rs:14:15
+  --> $DIR/struct-field-as-captured-argument.rs:14:23
    |
-LL |     format!("{foo.field} {} {baz}", "aa", baz = 3);
-   |               ^^^^^^^^^ not supported in format string
+LL |     let _ = format!("{foo.field} {} {baz}", "aa", baz = 3);
+   |                       ^^^^^^^^^ not supported in format string
    |
 help: consider using a positional formatting argument instead
    |
-LL |     format!("{1} {} {baz}", "aa", foo.field, baz = 3);
-   |               ~                 +++++++++++
+LL |     let _ = format!("{1} {} {baz}", "aa", foo.field, baz = 3);
+   |                       ~                 +++++++++++
 
 error: invalid format string: field access isn't supported
-  --> $DIR/struct-field-as-captured-argument.rs:15:15
+  --> $DIR/struct-field-as-captured-argument.rs:15:23
    |
-LL |     format!("{foo.field:?} {} {baz}", "aa", baz = 3);
-   |               ^^^^^^^^^ not supported in format string
+LL |     let _ = format!("{foo.field:?} {} {baz}", "aa", baz = 3);
+   |                       ^^^^^^^^^ not supported in format string
    |
 help: consider using a positional formatting argument instead
    |
-LL |     format!("{1:?} {} {baz}", "aa", foo.field, baz = 3);
-   |               ~                   +++++++++++
+LL |     let _ = format!("{1:?} {} {baz}", "aa", foo.field, baz = 3);
+   |                       ~                   +++++++++++
 
 error: invalid format string: field access isn't supported
-  --> $DIR/struct-field-as-captured-argument.rs:16:15
+  --> $DIR/struct-field-as-captured-argument.rs:16:23
    |
-LL |     format!("{foo.field:#?} {} {baz}", "aa", baz = 3);
-   |               ^^^^^^^^^ not supported in format string
+LL |     let _ = format!("{foo.field:#?} {} {baz}", "aa", baz = 3);
+   |                       ^^^^^^^^^ not supported in format string
    |
 help: consider using a positional formatting argument instead
    |
-LL |     format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3);
-   |               ~                    +++++++++++
+LL |     let _ = format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3);
+   |                       ~                    +++++++++++
 
 error: invalid format string: field access isn't supported
-  --> $DIR/struct-field-as-captured-argument.rs:17:15
+  --> $DIR/struct-field-as-captured-argument.rs:17:23
    |
-LL |     format!("{foo.field:.3} {} {baz}", "aa", baz = 3);
-   |               ^^^^^^^^^ not supported in format string
+LL |     let _ = format!("{foo.field:.3} {} {baz}", "aa", baz = 3);
+   |                       ^^^^^^^^^ not supported in format string
    |
 help: consider using a positional formatting argument instead
    |
-LL |     format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3);
-   |               ~                    +++++++++++
+LL |     let _ = format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3);
+   |                       ~                    +++++++++++
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr
index 0b3331b040d..5000601e90f 100644
--- a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr
+++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr
@@ -10,7 +10,7 @@ LL |     x = foo::<()>;
    |         ^^^^^^^^^ expected fn item, found a different fn item
    |
    = note: expected fn item `fn(F) -> F {bar::<F>}`
-              found fn item `fn(()) {foo::<()>}`
+              found fn item `fn(()) -> () {foo::<()>}`
 
 error[E0308]: mismatched types
   --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:27:9
@@ -26,7 +26,7 @@ LL |     let mut x = bar::<()>;
 LL |     x = foo::<I>;
    |         ^^^^^^^^ expected fn item, found a different fn item
    |
-   = note: expected fn item `fn(()) {bar::<()>}`
+   = note: expected fn item `fn(()) -> () {bar::<()>}`
               found fn item `fn(I) -> I {foo::<I>}`
 help: use parentheses to call this function
    |
diff --git a/tests/ui/fn/suggest-return-closure.stderr b/tests/ui/fn/suggest-return-closure.stderr
index d276ce8be2b..45c12b548e6 100644
--- a/tests/ui/fn/suggest-return-closure.stderr
+++ b/tests/ui/fn/suggest-return-closure.stderr
@@ -34,11 +34,13 @@ LL | fn fun() -> _ {
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/suggest-return-closure.rs:23:9
    |
-LL |     let x = String::new();
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |         x.push(c);
    |         ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = String::new();
+   |         +++
 
 error[E0597]: `x` does not live long enough
   --> $DIR/suggest-return-closure.rs:23:9
diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr
index 9b5d84b5b09..c5c4f2c4d23 100644
--- a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr
+++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `i32: Baz<Self>` is not satisfied
+error[E0277]: the trait bound `<Self as Foo>::Bar<()>: Eq<i32>` is not satisfied
   --> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30
    |
 LL |     type Bar<T>: Baz<Self> = i32;
diff --git a/tests/ui/generics/generic-function-item-where-type.rs b/tests/ui/generics/generic-function-item-where-type.rs
index 0e36018389e..e1b0578cadb 100644
--- a/tests/ui/generics/generic-function-item-where-type.rs
+++ b/tests/ui/generics/generic-function-item-where-type.rs
@@ -3,5 +3,4 @@ fn foo<U>() {}
 fn main() {
     foo::<main>()
     //~^ ERROR constant provided when a type was expected
-    //~| ERROR type annotations needed
 }
diff --git a/tests/ui/generics/generic-function-item-where-type.stderr b/tests/ui/generics/generic-function-item-where-type.stderr
index 5b0c9a8ee6d..00e62843cb4 100644
--- a/tests/ui/generics/generic-function-item-where-type.stderr
+++ b/tests/ui/generics/generic-function-item-where-type.stderr
@@ -7,13 +7,6 @@ LL |     foo::<main>()
    = help: `main` is a function item, not a type
    = help: function item types cannot be named directly
 
-error[E0282]: type annotations needed
-  --> $DIR/generic-function-item-where-type.rs:4:5
-   |
-LL |     foo::<main>()
-   |     ^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `foo`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0282, E0747.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/higher-ranked/well-formed-aliases.rs b/tests/ui/higher-ranked/well-formed-aliases.rs
new file mode 100644
index 00000000000..60e013a54bc
--- /dev/null
+++ b/tests/ui/higher-ranked/well-formed-aliases.rs
@@ -0,0 +1,8 @@
+trait Trait {
+    type Gat<U: ?Sized>;
+}
+
+fn test<T>(f: for<'a> fn(<&'a T as Trait>::Gat<&'a [str]>)) where for<'a> &'a T: Trait {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/well-formed-aliases.stderr b/tests/ui/higher-ranked/well-formed-aliases.stderr
new file mode 100644
index 00000000000..4a6f4e961d9
--- /dev/null
+++ b/tests/ui/higher-ranked/well-formed-aliases.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/well-formed-aliases.rs:5:52
+   |
+LL | fn test<T>(f: for<'a> fn(<&'a T as Trait>::Gat<&'a [str]>)) where for<'a> &'a T: Trait {}
+   |                                                    ^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: slice and array elements must have `Sized` type
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed
index 886fc1d0058..3c4499f0173 100644
--- a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed
+++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed
@@ -1,6 +1,8 @@
 //@ run-rustfix
 
+#[allow(dead_code)]
 struct S<T>(T);
+#[allow(dead_code)]
 struct S2;
 
 impl<T: Default> Default for S<T> {
diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs
index f3271993867..ac078329524 100644
--- a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs
+++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs
@@ -1,6 +1,8 @@
 //@ run-rustfix
 
+#[allow(dead_code)]
 struct S<T>(T);
+#[allow(dead_code)]
 struct S2;
 
 impl<T: Default> impl Default for S<T> {
diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr
index 5aafc8b64d4..91c7da5a04f 100644
--- a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr
+++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr
@@ -1,23 +1,23 @@
 error: unexpected `impl` keyword
-  --> $DIR/extra-impl-in-trait-impl.rs:6:18
+  --> $DIR/extra-impl-in-trait-impl.rs:8:18
    |
 LL | impl<T: Default> impl Default for S<T> {
    |                  ^^^^^ help: remove the extra `impl`
    |
 note: this is parsed as an `impl Trait` type, but a trait is expected at this position
-  --> $DIR/extra-impl-in-trait-impl.rs:6:18
+  --> $DIR/extra-impl-in-trait-impl.rs:8:18
    |
 LL | impl<T: Default> impl Default for S<T> {
    |                  ^^^^^^^^^^^^
 
 error: unexpected `impl` keyword
-  --> $DIR/extra-impl-in-trait-impl.rs:12:6
+  --> $DIR/extra-impl-in-trait-impl.rs:14:6
    |
 LL | impl impl Default for S2 {
    |      ^^^^^ help: remove the extra `impl`
    |
 note: this is parsed as an `impl Trait` type, but a trait is expected at this position
-  --> $DIR/extra-impl-in-trait-impl.rs:12:6
+  --> $DIR/extra-impl-in-trait-impl.rs:14:6
    |
 LL | impl impl Default for S2 {
    |      ^^^^^^^^^^^^
diff --git a/tests/ui/impl-trait/impl-generic-mismatch-ab.stderr b/tests/ui/impl-trait/impl-generic-mismatch-ab.stderr
index 7046e729e18..90c31c9e3fc 100644
--- a/tests/ui/impl-trait/impl-generic-mismatch-ab.stderr
+++ b/tests/ui/impl-trait/impl-generic-mismatch-ab.stderr
@@ -2,10 +2,8 @@ error[E0053]: method `foo` has an incompatible type for trait
   --> $DIR/impl-generic-mismatch-ab.rs:8:32
    |
 LL |     fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { }
-   |            -                   ^^^^^^^^^^^
-   |            |                   |
-   |            |                   expected type parameter `B`, found type parameter `impl Debug`
-   |            |                   help: change the parameter type to match the trait: `&B`
+   |            -                   ^^^^^^^^^^^ expected type parameter `B`, found type parameter `impl Debug`
+   |            |
    |            expected type parameter
    |
 note: type in trait
@@ -17,6 +15,10 @@ LL |     fn foo<A: Debug>(&self, a: &A, b: &impl Debug);
               found signature `fn(&(), &impl Debug, &B)`
    = 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
+help: change the parameter type to match the trait
+   |
+LL |     fn foo<B: Debug>(&self, a: &B, b: &B) { }
+   |                                ~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr
index 8e61a65abe4..75cbe43eeb4 100644
--- a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr
+++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr
@@ -27,10 +27,7 @@ LL |         type Ty = impl Sized;
    |                   ---------- the expected opaque type
 LL |
 LL |         fn method() -> () {}
-   |                        ^^
-   |                        |
-   |                        expected opaque type, found `()`
-   |                        help: change the output type to match the trait: `<() as compare_method::Trait>::Ty`
+   |                        ^^ expected opaque type, found `()`
    |
 note: type in trait
   --> $DIR/in-assoc-type-unconstrained.rs:17:24
@@ -38,12 +35,16 @@ note: type in trait
 LL |         fn method() -> Self::Ty;
    |                        ^^^^^^^^
    = note: expected signature `fn() -> <() as compare_method::Trait>::Ty`
-              found signature `fn()`
+              found signature `fn() -> ()`
 note: this item must have the opaque type in its signature in order to be able to register hidden types
   --> $DIR/in-assoc-type-unconstrained.rs:22:12
    |
 LL |         fn method() -> () {}
    |            ^^^^^^
+help: change the output type to match the trait
+   |
+LL |         fn method() -> <() as compare_method::Trait>::Ty {}
+   |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: unconstrained opaque type
   --> $DIR/in-assoc-type-unconstrained.rs:20:19
diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
new file mode 100644
index 00000000000..d71c1768a6a
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
@@ -0,0 +1,173 @@
+error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
+  --> $DIR/false-positive-predicate-entailment-error.rs:36:5
+   |
+LL | /     fn autobatch<F>(self) -> impl Trait
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     where
+LL | |         F: Callback<Self::CallbackArg>,
+   | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |
+note: required for `F` to implement `Callback<i32>`
+  --> $DIR/false-positive-predicate-entailment-error.rs:14:21
+   |
+LL | impl<A, F: MyFn<A>> Callback<A> for F {
+   |            -------  ^^^^^^^^^^^     ^
+   |            |
+   |            unsatisfied trait bound introduced here
+help: consider further restricting this bound
+   |
+LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
+   |                                        +++++++++++
+
+error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
+  --> $DIR/false-positive-predicate-entailment-error.rs:36:30
+   |
+LL |     fn autobatch<F>(self) -> impl Trait
+   |                              ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |
+note: required for `F` to implement `Callback<i32>`
+  --> $DIR/false-positive-predicate-entailment-error.rs:14:21
+   |
+LL | impl<A, F: MyFn<A>> Callback<A> for F {
+   |            -------  ^^^^^^^^^^^     ^
+   |            |
+   |            unsatisfied trait bound introduced here
+note: required by a bound in `<Sender as ChannelSender>::autobatch`
+  --> $DIR/false-positive-predicate-entailment-error.rs:43:12
+   |
+LL |     fn autobatch<F>(self) -> impl Trait
+   |        --------- required by a bound in this associated function
+...
+LL |         F: Callback<Self::CallbackArg>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<Sender as ChannelSender>::autobatch`
+help: consider further restricting this bound
+   |
+LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
+   |                                        +++++++++++
+
+error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
+  --> $DIR/false-positive-predicate-entailment-error.rs:36:5
+   |
+LL | /     fn autobatch<F>(self) -> impl Trait
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     where
+LL | |         F: Callback<Self::CallbackArg>,
+   | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |
+note: required for `F` to implement `Callback<i32>`
+  --> $DIR/false-positive-predicate-entailment-error.rs:14:21
+   |
+LL | impl<A, F: MyFn<A>> Callback<A> for F {
+   |            -------  ^^^^^^^^^^^     ^
+   |            |
+   |            unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider further restricting this bound
+   |
+LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
+   |                                        +++++++++++
+
+error[E0277]: the trait bound `F: Callback<i32>` is not satisfied
+  --> $DIR/false-positive-predicate-entailment-error.rs:43:12
+   |
+LL |         F: Callback<Self::CallbackArg>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |
+note: required for `F` to implement `Callback<i32>`
+  --> $DIR/false-positive-predicate-entailment-error.rs:14:21
+   |
+LL | impl<A, F: MyFn<A>> Callback<A> for F {
+   |            -------  ^^^^^^^^^^^     ^
+   |            |
+   |            unsatisfied trait bound introduced here
+note: the requirement `F: Callback<i32>` appears on the `impl`'s method `autobatch` but not on the corresponding trait's method
+  --> $DIR/false-positive-predicate-entailment-error.rs:25:8
+   |
+LL | trait ChannelSender {
+   |       ------------- in this trait
+...
+LL |     fn autobatch<F>(self) -> impl Trait
+   |        ^^^^^^^^^ this trait's method doesn't have the requirement `F: Callback<i32>`
+help: consider further restricting this bound
+   |
+LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
+   |                                        +++++++++++
+
+error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
+  --> $DIR/false-positive-predicate-entailment-error.rs:36:30
+   |
+LL |     fn autobatch<F>(self) -> impl Trait
+   |                              ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |
+note: required for `F` to implement `Callback<i32>`
+  --> $DIR/false-positive-predicate-entailment-error.rs:14:21
+   |
+LL | impl<A, F: MyFn<A>> Callback<A> for F {
+   |            -------  ^^^^^^^^^^^     ^
+   |            |
+   |            unsatisfied trait bound introduced here
+
+error[E0277]: the trait bound `F: Callback<i32>` is not satisfied
+  --> $DIR/false-positive-predicate-entailment-error.rs:27:12
+   |
+LL |         F: Callback<Self::CallbackArg>;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |
+note: required for `F` to implement `Callback<i32>`
+  --> $DIR/false-positive-predicate-entailment-error.rs:14:21
+   |
+LL | impl<A, F: MyFn<A>> Callback<A> for F {
+   |            -------  ^^^^^^^^^^^     ^
+   |            |
+   |            unsatisfied trait bound introduced here
+
+error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
+  --> $DIR/false-positive-predicate-entailment-error.rs:36:5
+   |
+LL | /     fn autobatch<F>(self) -> impl Trait
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     where
+LL | |         F: Callback<Self::CallbackArg>,
+   | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |
+note: required for `F` to implement `Callback<i32>`
+  --> $DIR/false-positive-predicate-entailment-error.rs:14:21
+   |
+LL | impl<A, F: MyFn<A>> Callback<A> for F {
+   |            -------  ^^^^^^^^^^^     ^
+   |            |
+   |            unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider further restricting this bound
+   |
+LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
+   |                                        +++++++++++
+
+error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
+  --> $DIR/false-positive-predicate-entailment-error.rs:43:12
+   |
+LL |         F: Callback<Self::CallbackArg>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`
+   |
+note: required by a bound in `Callback`
+  --> $DIR/false-positive-predicate-entailment-error.rs:10:20
+   |
+LL | trait Callback<A>: MyFn<A, Output = Self::Ret> {
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Callback`
+help: consider further restricting this bound
+   |
+LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
+   |                                        +++++++++++
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs
new file mode 100644
index 00000000000..59fdeab9e0a
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs
@@ -0,0 +1,51 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@[next] check-pass
+
+trait MyFn<T> {
+    type Output;
+}
+
+trait Callback<A>: MyFn<A, Output = Self::Ret> {
+    type Ret;
+}
+
+impl<A, F: MyFn<A>> Callback<A> for F {
+    type Ret = F::Output;
+}
+
+struct Thing;
+trait Trait {}
+impl Trait for Thing {}
+
+trait ChannelSender {
+    type CallbackArg;
+
+    fn autobatch<F>(self) -> impl Trait
+    where
+        F: Callback<Self::CallbackArg>;
+        //[current]~^ ERROR the trait bound `F: Callback<i32>` is not satisfied
+}
+
+struct Sender;
+
+impl ChannelSender for Sender {
+    type CallbackArg = i32;
+
+    fn autobatch<F>(self) -> impl Trait
+    //[current]~^ ERROR the trait bound `F: MyFn<i32>` is not satisfied
+    //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied
+    //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied
+    //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied
+    //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied
+    where
+        F: Callback<Self::CallbackArg>,
+        //[current]~^ ERROR the trait bound `F: Callback<i32>` is not satisfied
+        //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied
+    {
+        Thing
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr
index 2231205327c..6f6b787b6fe 100644
--- a/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr
@@ -2,10 +2,8 @@ error[E0053]: method `early` has an incompatible type for trait
   --> $DIR/method-signature-matches.rs:55:27
    |
 LL |     fn early<'late, T>(_: &'late ()) {}
-   |                     -     ^^^^^^^^^
-   |                     |     |
-   |                     |     expected type parameter `T`, found `()`
-   |                     |     help: change the parameter type to match the trait: `&T`
+   |                     -     ^^^^^^^^^ expected type parameter `T`, found `()`
+   |                     |
    |                     expected this type parameter
    |
 note: type in trait
@@ -15,6 +13,10 @@ LL |     fn early<'early, T>(x: &'early T) -> impl Sized;
    |                            ^^^^^^^^^
    = note: expected signature `fn(&T)`
               found signature `fn(&'late ())`
+help: change the parameter type to match the trait
+   |
+LL |     fn early<'late, T>(_: &T) {}
+   |                           ~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr
index ec2a126865d..9e18517e48c 100644
--- a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr
@@ -2,10 +2,7 @@ error[E0053]: method `owo` has an incompatible type for trait
   --> $DIR/method-signature-matches.rs:11:15
    |
 LL |     fn owo(_: u8) {}
-   |               ^^
-   |               |
-   |               expected `()`, found `u8`
-   |               help: change the parameter type to match the trait: `()`
+   |               ^^ expected `()`, found `u8`
    |
 note: type in trait
   --> $DIR/method-signature-matches.rs:6:15
@@ -14,6 +11,10 @@ LL |     fn owo(x: ()) -> impl Sized;
    |               ^^
    = note: expected signature `fn(())`
               found signature `fn(u8)`
+help: change the parameter type to match the trait
+   |
+LL |     fn owo(_: ()) {}
+   |               ~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr
index 4d3e64e8050..c01d7322d11 100644
--- a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr
@@ -2,10 +2,7 @@ error[E0053]: method `owo` has an incompatible type for trait
   --> $DIR/method-signature-matches.rs:22:21
    |
 LL |     async fn owo(_: u8) {}
-   |                     ^^
-   |                     |
-   |                     expected `()`, found `u8`
-   |                     help: change the parameter type to match the trait: `()`
+   |                     ^^ expected `()`, found `u8`
    |
 note: type in trait
   --> $DIR/method-signature-matches.rs:17:21
@@ -14,6 +11,10 @@ LL |     async fn owo(x: ()) {}
    |                     ^^
    = note: expected signature `fn(()) -> _`
               found signature `fn(u8) -> _`
+help: change the parameter type to match the trait
+   |
+LL |     async fn owo(_: ()) {}
+   |                     ~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
index d7fc40fa342..1f8a0d5edd7 100644
--- a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
@@ -75,10 +75,7 @@ error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/opaque-and-lifetime-mismatch.rs:10:17
    |
 LL |     fn bar() -> i32 {
-   |                 ^^^
-   |                 |
-   |                 expected `Wrapper<'static>`, found `i32`
-   |                 help: change the output type to match the trait: `Wrapper<'static>`
+   |                 ^^^ expected `Wrapper<'static>`, found `i32`
    |
 note: type in trait
   --> $DIR/opaque-and-lifetime-mismatch.rs:4:17
@@ -87,6 +84,10 @@ LL |     fn bar() -> Wrapper<impl Sized>;
    |                 ^^^^^^^^^^^^^^^^^^^
    = note: expected signature `fn() -> Wrapper<'static>`
               found signature `fn() -> i32`
+help: change the output type to match the trait
+   |
+LL |     fn bar() -> Wrapper<'static> {
+   |                 ~~~~~~~~~~~~~~~~
 
 error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/opaque-and-lifetime-mismatch.rs:24:17
diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.stderr
index b8a8e2401b2..8c9f2656015 100644
--- a/tests/ui/impl-trait/in-trait/specialization-broken.stderr
+++ b/tests/ui/impl-trait/in-trait/specialization-broken.stderr
@@ -5,10 +5,7 @@ LL | default impl<U> Foo for U
    |              - found this type parameter
 ...
 LL |     fn bar(&self) -> U {
-   |                      ^
-   |                      |
-   |                      expected associated type, found type parameter `U`
-   |                      help: change the output type to match the trait: `impl Sized`
+   |                      ^ expected associated type, found type parameter `U`
    |
 note: type in trait
   --> $DIR/specialization-broken.rs:8:22
@@ -17,6 +14,10 @@ LL |     fn bar(&self) -> impl Sized;
    |                      ^^^^^^^^^^
    = note: expected signature `fn(&_) -> impl Sized`
               found signature `fn(&_) -> U`
+help: change the output type to match the trait
+   |
+LL |     fn bar(&self) -> impl Sized {
+   |                      ~~~~~~~~~~
 
 error: method with return-position `impl Trait` in trait cannot be specialized
   --> $DIR/specialization-broken.rs:15:5
diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs
index 502b2af2bc6..760102794c3 100644
--- a/tests/ui/impl-trait/nested_impl_trait.rs
+++ b/tests/ui/impl-trait/nested_impl_trait.rs
@@ -5,7 +5,7 @@ fn fine(x: impl Into<u32>) -> impl Into<u32> { x }
 
 fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
 //~^ ERROR nested `impl Trait` is not allowed
-//~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
+//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
 
 fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
 //~^ ERROR nested `impl Trait` is not allowed
@@ -18,7 +18,7 @@ struct X;
 impl X {
     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
     //~^ ERROR nested `impl Trait` is not allowed
-    //~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
+    //~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
 }
 
 fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {
diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr
index a53312e5c0b..83d1347aff4 100644
--- a/tests/ui/impl-trait/nested_impl_trait.stderr
+++ b/tests/ui/impl-trait/nested_impl_trait.stderr
@@ -42,7 +42,7 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
+error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
   --> $DIR/nested_impl_trait.rs:6:46
    |
 LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
@@ -51,7 +51,7 @@ LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
    = help: the trait `Into<U>` is implemented for `T`
    = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
 
-error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied
+error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
   --> $DIR/nested_impl_trait.rs:19:34
    |
 LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
index 6d417488533..caaac5434c5 100644
--- a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
+++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
@@ -57,31 +57,35 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/opaque-used-in-extraneous-argument.rs:17:20
    |
 LL |     let old_path = frob("hello");
-   |                    ^^^^ -------
-   |                         |
-   |                         unexpected argument of type `&'static str`
-   |                         help: remove the extra argument
+   |                    ^^^^ ------- unexpected argument of type `&'static str`
    |
 note: function defined here
   --> $DIR/opaque-used-in-extraneous-argument.rs:5:4
    |
 LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
    |    ^^^^
+help: remove the extra argument
+   |
+LL -     let old_path = frob("hello");
+LL +     let old_path = frob();
+   |
 
 error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/opaque-used-in-extraneous-argument.rs:20:5
    |
 LL |     open_parent(&old_path)
-   |     ^^^^^^^^^^^ ---------
-   |                 |
-   |                 unexpected argument of type `&impl FnOnce<{type error}, Output = {type error}> + Fn<{type error}> + 'static`
-   |                 help: remove the extra argument
+   |     ^^^^^^^^^^^ --------- unexpected argument of type `&impl FnOnce<{type error}, Output = {type error}> + Fn<{type error}> + 'static`
    |
 note: function defined here
   --> $DIR/opaque-used-in-extraneous-argument.rs:12:4
    |
 LL | fn open_parent<'path>() {
    |    ^^^^^^^^^^^
+help: remove the extra argument
+   |
+LL -     open_parent(&old_path)
+LL +     open_parent()
+   |
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
index 4352af1c0df..3692cc77b0f 100644
--- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
+++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
@@ -26,13 +26,14 @@ LL |     type Foo = impl PartialEq<(Foo, i32)>;
    |                -------------------------- the found opaque type
 ...
 LL |         fn eq(&self, _other: &(Foo, i32)) -> bool {
-   |                              ^^^^^^^^^^^
-   |                              |
-   |                              expected `a::Bar`, found opaque type
-   |                              help: change the parameter type to match the trait: `&(a::Bar, i32)`
+   |                              ^^^^^^^^^^^ expected `a::Bar`, found opaque type
    |
    = note: expected signature `fn(&a::Bar, &(a::Bar, _)) -> _`
               found signature `fn(&a::Bar, &(a::Foo, _)) -> _`
+help: change the parameter type to match the trait
+   |
+LL |         fn eq(&self, _other: &(a::Bar, i32)) -> bool {
+   |                              ~~~~~~~~~~~~~~
 
 error: unconstrained opaque type
   --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:19:16
@@ -49,10 +50,7 @@ LL |     type Foo = impl PartialEq<(Foo, i32)>;
    |                -------------------------- the expected opaque type
 ...
 LL |         fn eq(&self, _other: &(Bar, i32)) -> bool {
-   |                              ^^^^^^^^^^^
-   |                              |
-   |                              expected opaque type, found `b::Bar`
-   |                              help: change the parameter type to match the trait: `&(b::Foo, i32)`
+   |                              ^^^^^^^^^^^ expected opaque type, found `b::Bar`
    |
    = note: expected signature `fn(&b::Bar, &(b::Foo, _)) -> _`
               found signature `fn(&b::Bar, &(b::Bar, _)) -> _`
@@ -61,6 +59,10 @@ note: this item must have the opaque type in its signature in order to be able t
    |
 LL |         fn eq(&self, _other: &(Bar, i32)) -> bool {
    |            ^^
+help: change the parameter type to match the trait
+   |
+LL |         fn eq(&self, _other: &(b::Foo, i32)) -> bool {
+   |                              ~~~~~~~~~~~~~~
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/impl-trait/trait_type.stderr b/tests/ui/impl-trait/trait_type.stderr
index 81e4c933e53..989779a6178 100644
--- a/tests/ui/impl-trait/trait_type.stderr
+++ b/tests/ui/impl-trait/trait_type.stderr
@@ -2,13 +2,14 @@ error[E0053]: method `fmt` has an incompatible type for trait
   --> $DIR/trait_type.rs:7:21
    |
 LL |    fn fmt(&self, x: &str) -> () { }
-   |                     ^^^^
-   |                     |
-   |                     types differ in mutability
-   |                     help: change the parameter type to match the trait: `&mut Formatter<'_>`
+   |                     ^^^^ types differ in mutability
    |
    = note: expected signature `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
-              found signature `fn(&MyType, &str)`
+              found signature `fn(&MyType, &str) -> ()`
+help: change the parameter type to match the trait
+   |
+LL |    fn fmt(&self, x: &mut Formatter<'_>) -> () { }
+   |                     ~~~~~~~~~~~~~~~~~~
 
 error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2
   --> $DIR/trait_type.rs:12:11
diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr
index bffe0447f8b..f0d259d01de 100644
--- a/tests/ui/impl-trait/where-allowed.stderr
+++ b/tests/ui/impl-trait/where-allowed.stderr
@@ -397,10 +397,7 @@ LL |     type Out = impl Debug;
    |                ---------- the expected opaque type
 ...
 LL |     fn in_trait_impl_return() -> impl Debug { () }
-   |                                  ^^^^^^^^^^
-   |                                  |
-   |                                  expected opaque type, found a different opaque type
-   |                                  help: change the output type to match the trait: `<() as DummyTrait>::Out`
+   |                                  ^^^^^^^^^^ expected opaque type, found a different opaque type
    |
 note: type in trait
   --> $DIR/where-allowed.rs:119:34
@@ -410,6 +407,10 @@ LL |     fn in_trait_impl_return() -> Self::Out;
    = note: expected signature `fn() -> <() as DummyTrait>::Out`
               found signature `fn() -> impl Debug`
    = note: distinct uses of `impl Trait` result in different opaque types
+help: change the output type to match the trait
+   |
+LL |     fn in_trait_impl_return() -> <() as DummyTrait>::Out { () }
+   |                                  ~~~~~~~~~~~~~~~~~~~~~~~
 
 error: unconstrained opaque type
   --> $DIR/where-allowed.rs:122:16
diff --git a/tests/ui/imports/suggest-import-issue-120074.rs b/tests/ui/imports/suggest-import-issue-120074.rs
new file mode 100644
index 00000000000..a798e9eeeb8
--- /dev/null
+++ b/tests/ui/imports/suggest-import-issue-120074.rs
@@ -0,0 +1,11 @@
+pub mod foo {
+    pub mod bar {
+        pub fn do_the_thing() -> usize {
+            42
+        }
+    }
+}
+
+fn main() {
+    println!("Hello, {}!", crate::bar::do_the_thing); //~ ERROR failed to resolve: unresolved import
+}
diff --git a/tests/ui/imports/suggest-import-issue-120074.stderr b/tests/ui/imports/suggest-import-issue-120074.stderr
new file mode 100644
index 00000000000..c1dff93bbdb
--- /dev/null
+++ b/tests/ui/imports/suggest-import-issue-120074.stderr
@@ -0,0 +1,23 @@
+error[E0433]: failed to resolve: unresolved import
+  --> $DIR/suggest-import-issue-120074.rs:10:35
+   |
+LL |     println!("Hello, {}!", crate::bar::do_the_thing);
+   |                                   ^^^ unresolved import
+   |
+help: a similar path exists
+   |
+LL |     println!("Hello, {}!", crate::foo::bar::do_the_thing);
+   |                                   ~~~~~~~~
+help: consider importing this module
+   |
+LL + use foo::bar;
+   |
+help: if you import `bar`, refer to it directly
+   |
+LL -     println!("Hello, {}!", crate::bar::do_the_thing);
+LL +     println!("Hello, {}!", bar::do_the_thing);
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr b/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr
index e2ddf474c4a..a5cd057e284 100644
--- a/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr
+++ b/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr
@@ -55,16 +55,18 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:21:31
    |
 LL |     LendingIterator::for_each(Query::new(&data), Box::new);
-   |                               ^^^^^^^^^^ -----
-   |                                          |
-   |                                          unexpected argument of type `&fn() {data}`
-   |                                          help: remove the extra argument
+   |                               ^^^^^^^^^^ ----- unexpected argument of type `&fn() {data}`
    |
 note: associated function defined here
   --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:17:12
    |
 LL |     pub fn new() -> Self {}
    |            ^^^
+help: remove the extra argument
+   |
+LL -     LendingIterator::for_each(Query::new(&data), Box::new);
+LL +     LendingIterator::for_each(Query::new(), Box::new);
+   |
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/intrinsics/not-overridden.rs b/tests/ui/intrinsics/not-overridden.rs
index a53071e304d..93b408331b8 100644
--- a/tests/ui/intrinsics/not-overridden.rs
+++ b/tests/ui/intrinsics/not-overridden.rs
@@ -1,6 +1,6 @@
 //! Check that intrinsics that do not get overridden, but are marked as such,
 //! cause an error instead of silently invoking the body.
-#![feature(rustc_attrs/* , effects*/)] // FIXME(effects)
+#![feature(rustc_attrs)]
 //@ build-fail
 //@ failure-status:101
 //@ normalize-stderr-test ".*note: .*\n\n" -> ""
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
new file mode 100644
index 00000000000..d9a4960feec
--- /dev/null
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
@@ -0,0 +1,52 @@
+error: using `#![feature(effects)]` without enabling next trait solver globally
+   |
+   = note: the next trait solver must be enabled globally for the effects feature to work correctly
+   = help: use `-Znext-solver` to enable
+
+error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
+  --> $DIR/safe-intrinsic-mismatch.rs:11:5
+   |
+LL |     fn size_of<T>() -> usize;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
+  --> $DIR/safe-intrinsic-mismatch.rs:11:5
+   |
+LL |     fn size_of<T>() -> usize;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume`
+  --> $DIR/safe-intrinsic-mismatch.rs:16:1
+   |
+LL | const fn assume(_b: bool) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: intrinsic has wrong type
+  --> $DIR/safe-intrinsic-mismatch.rs:16:16
+   |
+LL | const fn assume(_b: bool) {}
+   |                ^ expected unsafe fn, found safe fn
+   |
+   = note: expected signature `unsafe fn(_)`
+              found signature `fn(_)`
+
+error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `const_deallocate`
+  --> $DIR/safe-intrinsic-mismatch.rs:20:1
+   |
+LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: intrinsic has wrong type
+  --> $DIR/safe-intrinsic-mismatch.rs:20:26
+   |
+LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+   |                          ^ expected unsafe fn, found safe fn
+   |
+   = note: expected signature `unsafe fn(_, _, _)`
+              found signature `fn(_, _, _)`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs
index c116ba7a62e..af563e996c1 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs
@@ -1,6 +1,11 @@
+//@ revisions: stock effects
 #![feature(intrinsics)]
 #![feature(rustc_attrs)]
-// FIXME(effects) do this with revisions #![feature(effects)]
+// as effects insert a const generic param to const intrinsics,
+// check here that it doesn't report a const param mismatch either
+// enabling or disabling effects.
+#![cfg_attr(effects, feature(effects))]
+#![allow(incomplete_features)]
 
 extern "rust-intrinsic" {
     fn size_of<T>() -> usize; //~ ERROR intrinsic safety mismatch
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stock.stderr
index 7f37e0f8211..6864c0f36de 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stock.stderr
@@ -1,11 +1,11 @@
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
-  --> $DIR/safe-intrinsic-mismatch.rs:6:5
+  --> $DIR/safe-intrinsic-mismatch.rs:11:5
    |
 LL |     fn size_of<T>() -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
-  --> $DIR/safe-intrinsic-mismatch.rs:6:5
+  --> $DIR/safe-intrinsic-mismatch.rs:11:5
    |
 LL |     fn size_of<T>() -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,13 +13,13 @@ LL |     fn size_of<T>() -> usize;
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume`
-  --> $DIR/safe-intrinsic-mismatch.rs:11:1
+  --> $DIR/safe-intrinsic-mismatch.rs:16:1
    |
 LL | const fn assume(_b: bool) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: intrinsic has wrong type
-  --> $DIR/safe-intrinsic-mismatch.rs:11:16
+  --> $DIR/safe-intrinsic-mismatch.rs:16:16
    |
 LL | const fn assume(_b: bool) {}
    |                ^ expected unsafe fn, found safe fn
@@ -28,13 +28,13 @@ LL | const fn assume(_b: bool) {}
               found signature `fn(_)`
 
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `const_deallocate`
-  --> $DIR/safe-intrinsic-mismatch.rs:15:1
+  --> $DIR/safe-intrinsic-mismatch.rs:20:1
    |
 LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: intrinsic has wrong type
-  --> $DIR/safe-intrinsic-mismatch.rs:15:26
+  --> $DIR/safe-intrinsic-mismatch.rs:20:26
    |
 LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
    |                          ^ expected unsafe fn, found safe fn
diff --git a/tests/ui/issues/issue-11004.stderr b/tests/ui/issues/issue-11004.stderr
index ea141e61df8..6d157c91130 100644
--- a/tests/ui/issues/issue-11004.stderr
+++ b/tests/ui/issues/issue-11004.stderr
@@ -2,19 +2,23 @@ error[E0609]: no field `x` on type `*mut A`
   --> $DIR/issue-11004.rs:7:21
    |
 LL |     let x : i32 = n.x;
-   |                   --^
-   |                   | |
-   |                   | unknown field
-   |                   help: `n` is a raw pointer; try dereferencing it: `(*n).x`
+   |                     ^ unknown field
+   |
+help: `n` is a raw pointer; try dereferencing it
+   |
+LL |     let x : i32 = (*n).x;
+   |                   ++ +
 
 error[E0609]: no field `y` on type `*mut A`
   --> $DIR/issue-11004.rs:8:21
    |
 LL |     let y : f64 = n.y;
-   |                   --^
-   |                   | |
-   |                   | unknown field
-   |                   help: `n` is a raw pointer; try dereferencing it: `(*n).y`
+   |                     ^ unknown field
+   |
+help: `n` is a raw pointer; try dereferencing it
+   |
+LL |     let y : f64 = (*n).y;
+   |                   ++ +
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-16939.stderr b/tests/ui/issues/issue-16939.stderr
index 229ff9f1817..6e0889b8963 100644
--- a/tests/ui/issues/issue-16939.stderr
+++ b/tests/ui/issues/issue-16939.stderr
@@ -2,16 +2,18 @@ error[E0057]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/issue-16939.rs:5:9
    |
 LL |     |t| f(t);
-   |         ^ -
-   |           |
-   |           unexpected argument
-   |           help: remove the extra argument
+   |         ^ - unexpected argument
    |
 note: callable defined here
   --> $DIR/issue-16939.rs:4:12
    |
 LL | fn _foo<F: Fn()> (f: F) {
    |            ^^^^
+help: remove the extra argument
+   |
+LL -     |t| f(t);
+LL +     |t| f();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-20225.stderr b/tests/ui/issues/issue-20225.stderr
index 2d24a5bbd50..7d6b09cf7f8 100644
--- a/tests/ui/issues/issue-20225.stderr
+++ b/tests/ui/issues/issue-20225.stderr
@@ -4,13 +4,14 @@ error[E0053]: method `call` has an incompatible type for trait
 LL | impl<'a, T> Fn<(&'a T,)> for Foo {
    |          - found this type parameter
 LL |   extern "rust-call" fn call(&self, (_,): (T,)) {}
-   |                                           ^^^^
-   |                                           |
-   |                                           expected `&'a T`, found type parameter `T`
-   |                                           help: change the parameter type to match the trait: `(&'a T,)`
+   |                                           ^^^^ expected `&'a T`, found type parameter `T`
    |
    = note: expected signature `extern "rust-call" fn(&Foo, (&'a _,))`
               found signature `extern "rust-call" fn(&Foo, (_,))`
+help: change the parameter type to match the trait
+   |
+LL |   extern "rust-call" fn call(&self, (_,): (&'a T,)) {}
+   |                                           ~~~~~~~~
 
 error[E0053]: method `call_mut` has an incompatible type for trait
   --> $DIR/issue-20225.rs:11:51
@@ -18,13 +19,14 @@ error[E0053]: method `call_mut` has an incompatible type for trait
 LL | impl<'a, T> FnMut<(&'a T,)> for Foo {
    |          - found this type parameter
 LL |   extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
-   |                                                   ^^^^
-   |                                                   |
-   |                                                   expected `&'a T`, found type parameter `T`
-   |                                                   help: change the parameter type to match the trait: `(&'a T,)`
+   |                                                   ^^^^ expected `&'a T`, found type parameter `T`
    |
    = note: expected signature `extern "rust-call" fn(&mut Foo, (&'a _,))`
               found signature `extern "rust-call" fn(&mut Foo, (_,))`
+help: change the parameter type to match the trait
+   |
+LL |   extern "rust-call" fn call_mut(&mut self, (_,): (&'a T,)) {}
+   |                                                   ~~~~~~~~
 
 error[E0053]: method `call_once` has an incompatible type for trait
   --> $DIR/issue-20225.rs:18:47
@@ -33,13 +35,14 @@ LL | impl<'a, T> FnOnce<(&'a T,)> for Foo {
    |          - found this type parameter
 ...
 LL |   extern "rust-call" fn call_once(self, (_,): (T,)) {}
-   |                                               ^^^^
-   |                                               |
-   |                                               expected `&'a T`, found type parameter `T`
-   |                                               help: change the parameter type to match the trait: `(&'a T,)`
+   |                                               ^^^^ expected `&'a T`, found type parameter `T`
    |
    = note: expected signature `extern "rust-call" fn(Foo, (&'a _,))`
               found signature `extern "rust-call" fn(Foo, (_,))`
+help: change the parameter type to match the trait
+   |
+LL |   extern "rust-call" fn call_once(self, (_,): (&'a T,)) {}
+   |                                               ~~~~~~~~
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/issues/issue-20676.rs b/tests/ui/issues/issue-20676.rs
index b3319950b42..2059365c7d6 100644
--- a/tests/ui/issues/issue-20676.rs
+++ b/tests/ui/issues/issue-20676.rs
@@ -8,5 +8,5 @@ use std::fmt;
 
 fn main() {
     let a: &dyn fmt::Debug = &1;
-    format!("{:?}", a);
+    let _ = format!("{:?}", a);
 }
diff --git a/tests/ui/issues/issue-21332.stderr b/tests/ui/issues/issue-21332.stderr
index 96e0f5fdb31..7c960f7646d 100644
--- a/tests/ui/issues/issue-21332.stderr
+++ b/tests/ui/issues/issue-21332.stderr
@@ -2,13 +2,14 @@ error[E0053]: method `next` has an incompatible type for trait
   --> $DIR/issue-21332.rs:5:27
    |
 LL |     fn next(&mut self) -> Result<i32, i32> { Ok(7) }
-   |                           ^^^^^^^^^^^^^^^^
-   |                           |
-   |                           expected `Option<i32>`, found `Result<i32, i32>`
-   |                           help: change the output type to match the trait: `Option<i32>`
+   |                           ^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Result<i32, i32>`
    |
    = note: expected signature `fn(&mut S) -> Option<i32>`
               found signature `fn(&mut S) -> Result<i32, i32>`
+help: change the output type to match the trait
+   |
+LL |     fn next(&mut self) -> Option<i32> { Ok(7) }
+   |                           ~~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-21950.stderr b/tests/ui/issues/issue-21950.stderr
index e498565d4e6..584370c7178 100644
--- a/tests/ui/issues/issue-21950.stderr
+++ b/tests/ui/issues/issue-21950.stderr
@@ -14,9 +14,13 @@ LL | trait Add<Rhs=Self> {
    | ------------------- type parameter `Rhs` must be specified for this
 ...
 LL |     let x = &10 as &dyn Add;
-   |                         ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
+   |                         ^^^
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
+help: set the type parameter to the desired type
+   |
+LL |     let x = &10 as &dyn Add<Rhs>;
+   |                            +++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-22370.stderr b/tests/ui/issues/issue-22370.stderr
index 977cfe06bb8..3dc060963f9 100644
--- a/tests/ui/issues/issue-22370.stderr
+++ b/tests/ui/issues/issue-22370.stderr
@@ -5,9 +5,13 @@ LL | trait A<T=Self> {}
    | --------------- type parameter `T` must be specified for this
 LL |
 LL | fn f(a: &dyn A) {}
-   |              ^ help: set the type parameter to the desired type: `A<T>`
+   |              ^
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
+help: set the type parameter to the desired type
+   |
+LL | fn f(a: &dyn A<T>) {}
+   |               +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-22638.rs b/tests/ui/issues/issue-22638.rs
index 3e04eb41b98..3e401e99fb4 100644
--- a/tests/ui/issues/issue-22638.rs
+++ b/tests/ui/issues/issue-22638.rs
@@ -1,7 +1,4 @@
 //@ build-fail
-//@ normalize-stderr-test: "<\{closure@.+`" -> "$$CLOSURE`"
-//@ normalize-stderr-test: ".nll/" -> "/"
-//@ ignore-compare-mode-next-solver (hangs)
 
 #![allow(unused)]
 
@@ -43,6 +40,7 @@ impl C {
     pub fn matches<F: Fn()>(&self, f: &F) {
         let &C(ref base) = self;
         base.matches(&|| {
+            //~^ ERROR reached the type-length limit
             C(base.clone()).matches(f)
         })
     }
@@ -55,7 +53,6 @@ impl D {
     pub fn matches<F: Fn()>(&self, f: &F) {
         let &D(ref a) = self;
         a.matches(f)
-        //~^ ERROR reached the recursion limit while instantiating `A::matches::<{closure
     }
 }
 
diff --git a/tests/ui/issues/issue-22638.stderr b/tests/ui/issues/issue-22638.stderr
index 45290f6afe9..1344409c770 100644
--- a/tests/ui/issues/issue-22638.stderr
+++ b/tests/ui/issues/issue-22638.stderr
@@ -1,14 +1,13 @@
-error: reached the recursion limit while instantiating `A::matches::$CLOSURE`
-  --> $DIR/issue-22638.rs:57:9
+error: reached the type-length limit while instantiating `D::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>`
+  --> $DIR/issue-22638.rs:42:9
    |
-LL |         a.matches(f)
-   |         ^^^^^^^^^^^^
+LL | /         base.matches(&|| {
+LL | |
+LL | |             C(base.clone()).matches(f)
+LL | |         })
+   | |__________^
    |
-note: `A::matches` defined here
-  --> $DIR/issue-22638.rs:16:5
-   |
-LL |     pub fn matches<F: Fn()>(&self, f: &F) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: consider adding a `#![type_length_limit="30408681"]` attribute to your crate
 
 error: aborting due to 1 previous error
 
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 1646f16e1ec..131c7535537 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,6 +1,5 @@
 //@ build-fail
 //@ normalize-stderr-test: ".nll/" -> "/"
-//@ ignore-compare-mode-next-solver (hangs)
 
 trait Mirror {
     type Image;
@@ -15,7 +14,8 @@ trait Foo {
 impl<T> Foo for T {
     #[allow(unconditional_recursion)]
     fn recurse(&self) {
-        (self, self).recurse(); //~ ERROR reached the recursion limit
+        (self, self).recurse();
+        //~^ ERROR reached the type-length limit
     }
 }
 
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 ccee9ed4daa..2978ced5279 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,14 +1,10 @@
-error: reached the recursion limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse`
-  --> $DIR/issue-37311.rs:18:9
+error: reached the type-length limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse`
+  --> $DIR/issue-37311.rs:17:9
    |
 LL |         (self, self).recurse();
    |         ^^^^^^^^^^^^^^^^^^^^^^
    |
-note: `<T as Foo>::recurse` defined here
-  --> $DIR/issue-37311.rs:17:5
-   |
-LL |     fn recurse(&self) {
-   |     ^^^^^^^^^^^^^^^^^
+   = help: consider adding a `#![type_length_limit="33554429"]` attribute to your crate
    = 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'
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/issues/issue-4935.stderr b/tests/ui/issues/issue-4935.stderr
index 25f299ae5f3..f18cf66f14d 100644
--- a/tests/ui/issues/issue-4935.stderr
+++ b/tests/ui/issues/issue-4935.stderr
@@ -2,16 +2,18 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/issue-4935.rs:5:13
    |
 LL | fn main() { foo(5, 6) }
-   |             ^^^  ---
-   |                  | |
-   |                  | unexpected argument of type `{integer}`
-   |                  help: remove the extra argument
+   |             ^^^    - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/issue-4935.rs:3:4
    |
 LL | fn foo(a: usize) {}
    |    ^^^ --------
+help: remove the extra argument
+   |
+LL - fn main() { foo(5, 6) }
+LL + fn main() { foo(5) }
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs
index 9904eddb598..4f3ddce69d8 100644
--- a/tests/ui/iterators/issue-58952-filter-type-length.rs
+++ b/tests/ui/iterators/issue-58952-filter-type-length.rs
@@ -1,5 +1,5 @@
-//@ run-pass
-//@ ignore-compare-mode-next-solver (hangs)
+//@ build-fail
+//@ error-pattern: reached the type-length limit while instantiating
 
 //! This snippet causes the type length to blowup exponentially,
 //! so check that we don't accidentally exceed the type length limit.
@@ -30,5 +30,9 @@ fn main() {
         .filter(|a| b.clone().any(|b| *b == *a))
         .filter(|a| b.clone().any(|b| *b == *a))
         .filter(|a| b.clone().any(|b| *b == *a))
+        .filter(|a| b.clone().any(|b| *b == *a))
+        .filter(|a| b.clone().any(|b| *b == *a))
+        .filter(|a| b.clone().any(|b| *b == *a))
+        .filter(|a| b.clone().any(|b| *b == *a))
         .collect::<VecDeque<_>>();
 }
diff --git a/tests/ui/iterators/issue-58952-filter-type-length.stderr b/tests/ui/iterators/issue-58952-filter-type-length.stderr
new file mode 100644
index 00000000000..975fcd4afff
--- /dev/null
+++ b/tests/ui/iterators/issue-58952-filter-type-length.stderr
@@ -0,0 +1,8 @@
+error: reached the type-length limit while instantiating `<std::vec::IntoIter<i32> as Iterator>::try_fold::<vec::in_place_drop::InPlaceDrop<i32>, {closure@iter::adapters::filter::filter_try_fold<'_, ..., ..., ..., ..., ...>::{closure#0}}, ...>`
+  --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
+   |
+   = help: consider adding a `#![type_length_limit="21233607"]` attribute to your crate
+   = note: the full type name has been written to '$TEST_BUILD_DIR/iterators/issue-58952-filter-type-length/issue-58952-filter-type-length.long-type.txt'
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/iterators/iter-map-fold-type-length.rs b/tests/ui/iterators/iter-map-fold-type-length.rs
index 6444fb9dada..5f9567d68e8 100644
--- a/tests/ui/iterators/iter-map-fold-type-length.rs
+++ b/tests/ui/iterators/iter-map-fold-type-length.rs
@@ -3,7 +3,7 @@
 //!
 //! The normal limit is a million, and this test used to exceed 1.5 million, but
 //! now we can survive an even tighter limit. Still seems excessive though...
-#![type_length_limit = "256000"]
+#![type_length_limit = "1327047"]
 
 // Custom wrapper so Iterator methods aren't specialized.
 struct Iter<I>(I);
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
index aa1b1b73bae..2672efe51c9 100644
--- a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
@@ -5,7 +5,7 @@ LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpi
    |                                                                                   ^ expected `isize`, found `()`
    |
    = note: expected signature `fn(fn() -> _, _, _, _) -> isize`
-              found signature `fn(fn() -> _, _, _, _)`
+              found signature `fn(fn() -> _, _, _, _) -> ()`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/let-else/let-else-slicing-error.stderr b/tests/ui/let-else/let-else-slicing-error.stderr
index 73c357dd5d4..4daae861965 100644
--- a/tests/ui/let-else/let-else-slicing-error.stderr
+++ b/tests/ui/let-else/let-else-slicing-error.stderr
@@ -2,9 +2,12 @@ error[E0529]: expected an array or slice, found `Vec<{integer}>`
   --> $DIR/let-else-slicing-error.rs:6:9
    |
 LL |     let [x, y] = nums else {
-   |         ^^^^^^   ---- help: consider slicing here: `nums[..]`
-   |         |
-   |         pattern cannot match with input type `Vec<{integer}>`
+   |         ^^^^^^ pattern cannot match with input type `Vec<{integer}>`
+   |
+help: consider slicing here
+   |
+LL |     let [x, y] = nums[..] else {
+   |                      ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
index 0980de92d35..29bf7e62985 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
@@ -16,10 +16,13 @@ LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: &'a u32) {
 error[E0384]: cannot assign to immutable argument `y`
   --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5
    |
-LL | fn foo(mut x: Ref, y: &u32) {
-   |                    - help: consider making this binding mutable: `mut y`
 LL |     y = x.b;
    |     ^^^^^^^ cannot assign to immutable argument
+   |
+help: consider making this binding mutable
+   |
+LL | fn foo(mut x: Ref, mut y: &u32) {
+   |                    +++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr b/tests/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
index b47a47d631e..3fbd863467d 100644
--- a/tests/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/liveness-assign-imm-local-notes.stderr
@@ -1,45 +1,53 @@
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/liveness-assign-imm-local-notes.rs:10:9
    |
-LL |     let x;
-   |         - help: consider making this binding mutable: `mut x`
-...
 LL |         x = 2;
    |         ----- first assignment to `x`
 LL |         x = 3;
    |         ^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut x;
+   |         +++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/liveness-assign-imm-local-notes.rs:21:13
    |
-LL |         let x;
-   |             - help: consider making this binding mutable: `mut x`
-...
 LL |             x = 2;
    |             ----- first assignment to `x`
 LL |             x = 3;
    |             ^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |         let mut x;
+   |             +++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/liveness-assign-imm-local-notes.rs:30:13
    |
-LL |     let x;
-   |         - help: consider making this binding mutable: `mut x`
-...
 LL |             x = 1;
    |             ^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut x;
+   |         +++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/liveness-assign-imm-local-notes.rs:32:13
    |
-LL |     let x;
-   |         - help: consider making this binding mutable: `mut x`
-...
 LL |             x = 1;
    |             ----- first assignment to `x`
 LL |         } else {
 LL |             x = 2;
    |             ^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut x;
+   |         +++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs b/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs
index aa8236b7431..0d34bf988ef 100644
--- a/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs
+++ b/tests/ui/linkage-attr/unreferenced-used-static-issue-127052.rs
@@ -1,9 +1,10 @@
-// This is a non-regression test for issue #127052 where unreferenced `#[used]` statics couldn't be
-// removed by the MSVC linker, causing linking errors.
+// This is a non-regression test for issue #127052 where unreferenced `#[used]` statics in the
+// binary crate would be marked as "exported", but not be present in the binary, causing linking
+// errors with the MSVC linker.
 
 //@ build-pass: needs linking
-//@ only-msvc
 
 #[used]
 static FOO: u32 = 0;
+
 fn main() {}
diff --git a/tests/ui/lint/dead-code/issue-59003.rs b/tests/ui/lint/dead-code/issue-59003.rs
index e3dcaca5778..319cf2db149 100644
--- a/tests/ui/lint/dead-code/issue-59003.rs
+++ b/tests/ui/lint/dead-code/issue-59003.rs
@@ -4,8 +4,8 @@
 
 #![deny(dead_code)]
 
+#[allow(dead_code)]
 struct Foo {
-    #[allow(dead_code)]
     inner: u32,
 }
 
diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs
new file mode 100644
index 00000000000..25777438456
--- /dev/null
+++ b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs
@@ -0,0 +1,37 @@
+#![deny(dead_code)]
+
+struct Foo(u8); //~ ERROR struct `Foo` is never constructed
+
+enum Bar { //~ ERROR enum `Bar` is never used
+    Var1(u8),
+    Var2(u8),
+}
+
+pub trait Tr1 {
+    fn f1() -> Self;
+}
+
+impl Tr1 for Foo {
+    fn f1() -> Foo {
+        let f = Foo(0);
+        let Foo(tag) = f;
+        Foo(tag)
+    }
+}
+
+impl Tr1 for Bar {
+    fn f1() -> Bar {
+        let b = Bar::Var1(0);
+        let b = if let Bar::Var1(_) = b {
+            Bar::Var1(0)
+        } else {
+            Bar::Var2(0)
+        };
+        match b {
+            Bar::Var1(_) => Bar::Var2(0),
+            Bar::Var2(_) => Bar::Var1(0),
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr
new file mode 100644
index 00000000000..7c1a4b45977
--- /dev/null
+++ b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr
@@ -0,0 +1,20 @@
+error: struct `Foo` is never constructed
+  --> $DIR/lint-unused-adt-appeared-in-pattern.rs:3:8
+   |
+LL | struct Foo(u8);
+   |        ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-adt-appeared-in-pattern.rs:1:9
+   |
+LL | #![deny(dead_code)]
+   |         ^^^^^^^^^
+
+error: enum `Bar` is never used
+  --> $DIR/lint-unused-adt-appeared-in-pattern.rs:5:6
+   |
+LL | enum Bar {
+   |      ^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs b/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs
new file mode 100644
index 00000000000..43a2e431904
--- /dev/null
+++ b/tests/ui/lint/dead-code/not-lint-used-adt-appeared-in-pattern.rs
@@ -0,0 +1,32 @@
+//@ check-pass
+
+#![deny(dead_code)]
+
+#[repr(u8)]
+#[derive(Copy, Clone, Debug)]
+pub enum RecordField {
+    Target = 1,
+    Level,
+    Module,
+    File,
+    Line,
+    NumArgs,
+}
+
+unsafe trait Pod {}
+
+#[repr(transparent)]
+struct RecordFieldWrapper(RecordField);
+
+unsafe impl Pod for RecordFieldWrapper {}
+
+fn try_read<T: Pod>(buf: &[u8]) -> T {
+    unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const T) }
+}
+
+pub fn foo(buf: &[u8]) -> RecordField {
+    let RecordFieldWrapper(tag) = try_read(buf);
+    tag
+}
+
+fn main() {}
diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs
index bf2fc243e81..658cc3d6c61 100644
--- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs
+++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs
@@ -1,8 +1,9 @@
 #![deny(dead_code)]
 
 struct T1; //~ ERROR struct `T1` is never constructed
-pub struct T2(i32); //~ ERROR struct `T2` is never constructed
-struct T3;
+struct T2; //~ ERROR struct `T2` is never constructed
+pub struct T3(i32); //~ ERROR struct `T3` is never constructed
+pub struct T4(i32); //~ ERROR field `0` is never read
 
 trait Trait1 { //~ ERROR trait `Trait1` is never used
     const UNUSED: i32;
@@ -11,13 +12,13 @@ trait Trait1 { //~ ERROR trait `Trait1` is never used
 }
 
 pub trait Trait2 {
-    const USED: i32;
-    fn used(&self) {}
+    const MAY_USED: i32;
+    fn may_used(&self) {}
 }
 
 pub trait Trait3 {
-    const USED: i32;
-    fn construct_self() -> Self;
+    const MAY_USED: i32;
+    fn may_used() -> Self;
 }
 
 impl Trait1 for T1 {
@@ -30,23 +31,34 @@ impl Trait1 for T1 {
 impl Trait1 for T2 {
     const UNUSED: i32 = 0;
     fn construct_self() -> Self {
-        T2(0)
+        Self
     }
 }
 
 impl Trait2 for T1 {
-    const USED: i32 = 0;
+    const MAY_USED: i32 = 0;
 }
 
 impl Trait2 for T2 {
-    const USED: i32 = 0;
+    const MAY_USED: i32 = 0;
 }
 
-impl Trait3 for T3 {
-    const USED: i32 = 0;
-    fn construct_self() -> Self {
+impl Trait2 for T3 {
+    const MAY_USED: i32 = 0;
+}
+
+impl Trait3 for T2 {
+    const MAY_USED: i32 = 0;
+    fn may_used() -> Self {
         Self
     }
 }
 
+impl Trait3 for T4 {
+    const MAY_USED: i32 = 0;
+    fn may_used() -> Self {
+        T4(0)
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr
index 174096d9398..08c7a5cb4b0 100644
--- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr
+++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr
@@ -11,16 +11,32 @@ LL | #![deny(dead_code)]
    |         ^^^^^^^^^
 
 error: struct `T2` is never constructed
-  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:12
+  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:8
    |
-LL | pub struct T2(i32);
+LL | struct T2;
+   |        ^^
+
+error: struct `T3` is never constructed
+  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:5:12
+   |
+LL | pub struct T3(i32);
    |            ^^
 
+error: field `0` is never read
+  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:6:15
+   |
+LL | pub struct T4(i32);
+   |            -- ^^^
+   |            |
+   |            field in this struct
+   |
+   = help: consider removing this field
+
 error: trait `Trait1` is never used
-  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:7:7
+  --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:8:7
    |
 LL | trait Trait1 {
    |       ^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.rs b/tests/ui/lint/dead-code/unused-struct-derive-default.rs
index 330ad32dd57..f20b7cb66ee 100644
--- a/tests/ui/lint/dead-code/unused-struct-derive-default.rs
+++ b/tests/ui/lint/dead-code/unused-struct-derive-default.rs
@@ -22,4 +22,5 @@ pub struct T2 {
 
 fn main() {
     let _x: Used = Default::default();
+    let _e: E = Default::default();
 }
diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr
index bbb0bd7be70..7422f9a39f3 100644
--- a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr
+++ b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr
@@ -4,7 +4,6 @@ error: struct `T` is never constructed
 LL | struct T;
    |        ^
    |
-   = note: `T` has a derived impl for the trait `Default`, but this is intentionally ignored during dead code analysis
 note: the lint level is defined here
   --> $DIR/unused-struct-derive-default.rs:1:9
    |
diff --git a/tests/ui/lint/lint-unconditional-recursion-tail-calls.rs b/tests/ui/lint/lint-unconditional-recursion-tail-calls.rs
new file mode 100644
index 00000000000..c94bf032579
--- /dev/null
+++ b/tests/ui/lint/lint-unconditional-recursion-tail-calls.rs
@@ -0,0 +1,24 @@
+#![allow(incomplete_features, dead_code)]
+#![deny(unconditional_recursion)] //~ note: the lint level is defined here
+#![feature(explicit_tail_calls)]
+
+fn f(x: bool) {
+    //~^ error: function cannot return without recursing
+    //~| note: cannot return without recursing
+    if x {
+        become f(!x)
+    } else {
+        f(!x) //~ note: recursive call site
+    }
+}
+
+// This should *not* lint, tail-recursive functions which never return is a reasonable thing
+fn g(x: bool) {
+    if x {
+        become g(!x)
+    } else {
+        become g(!x)
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/lint-unconditional-recursion-tail-calls.stderr b/tests/ui/lint/lint-unconditional-recursion-tail-calls.stderr
new file mode 100644
index 00000000000..52f9740d027
--- /dev/null
+++ b/tests/ui/lint/lint-unconditional-recursion-tail-calls.stderr
@@ -0,0 +1,18 @@
+error: function cannot return without recursing
+  --> $DIR/lint-unconditional-recursion-tail-calls.rs:5:1
+   |
+LL | fn f(x: bool) {
+   | ^^^^^^^^^^^^^ cannot return without recursing
+...
+LL |         f(!x)
+   |         ----- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+note: the lint level is defined here
+  --> $DIR/lint-unconditional-recursion-tail-calls.rs:2:9
+   |
+LL | #![deny(unconditional_recursion)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs
index 08911c5bde7..d2f32a47122 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs
@@ -1,7 +1,7 @@
 fn test() {
     let v: isize;
     //~^ HELP consider making this binding mutable
-    //~| SUGGESTION mut v
+    //~| SUGGESTION mut
     loop {
         v = 1; //~ ERROR cannot assign twice to immutable variable `v`
                //~| NOTE cannot assign twice to immutable variable
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr
index f0174560fd5..e8c0721b903 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr
@@ -1,11 +1,13 @@
 error[E0384]: cannot assign twice to immutable variable `v`
   --> $DIR/liveness-assign-imm-local-in-loop.rs:6:9
    |
-LL |     let v: isize;
-   |         - help: consider making this binding mutable: `mut v`
-...
 LL |         v = 1;
    |         ^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut v: isize;
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs
index 1752d969086..fd6b4bcdf84 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs
@@ -1,7 +1,7 @@
 fn test() {
     let v: isize;
     //~^ HELP consider making this binding mutable
-    //~| SUGGESTION mut v
+    //~| SUGGESTION mut
     v = 2;  //~ NOTE first assignment
     v += 1; //~ ERROR cannot assign twice to immutable variable `v`
             //~| NOTE cannot assign twice to immutable
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr
index 578a40e4070..b7373d7cf1d 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr
@@ -1,13 +1,15 @@
 error[E0384]: cannot assign twice to immutable variable `v`
   --> $DIR/liveness-assign-imm-local-in-op-eq.rs:6:5
    |
-LL |     let v: isize;
-   |         - help: consider making this binding mutable: `mut v`
-...
 LL |     v = 2;
    |     ----- first assignment to `v`
 LL |     v += 1;
    |     ^^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut v: isize;
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs
index c9b16e43910..b7050d69306 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs
@@ -1,7 +1,7 @@
 fn test() {
     let b = Box::new(1); //~ NOTE first assignment
                          //~| HELP consider making this binding mutable
-                         //~| SUGGESTION mut b
+                         //~| SUGGESTION mut
     drop(b);
     b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b`
                      //~| NOTE cannot assign twice to immutable
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr
index 2f55b50f0ba..35b47bd6d91 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr
@@ -2,13 +2,15 @@ error[E0384]: cannot assign twice to immutable variable `b`
   --> $DIR/liveness-assign-imm-local-with-drop.rs:6:5
    |
 LL |     let b = Box::new(1);
-   |         -
-   |         |
-   |         first assignment to `b`
-   |         help: consider making this binding mutable: `mut b`
+   |         - first assignment to `b`
 ...
 LL |     b = Box::new(2);
    |     ^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut b = Box::new(1);
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs
index 4bb2db27a16..67c97e38546 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs
@@ -1,7 +1,7 @@
 fn test() {
     let v: isize = 1; //~ NOTE first assignment
                       //~| HELP consider making this binding mutable
-                      //~| SUGGESTION mut v
+                      //~| SUGGESTION mut
     v.clone();
     v = 2; //~ ERROR cannot assign twice to immutable variable `v`
            //~| NOTE cannot assign twice to immutable
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr
index 8eb71cd99bf..d1f9e1573e4 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr
@@ -2,13 +2,15 @@ error[E0384]: cannot assign twice to immutable variable `v`
   --> $DIR/liveness-assign-imm-local-with-init.rs:6:5
    |
 LL |     let v: isize = 1;
-   |         -
-   |         |
-   |         first assignment to `v`
-   |         help: consider making this binding mutable: `mut v`
+   |         - first assignment to `v`
 ...
 LL |     v = 2;
    |     ^^^^^ cannot assign twice to immutable variable
+   |
+help: consider making this binding mutable
+   |
+LL |     let mut v: isize = 1;
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.fixed b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed
new file mode 100644
index 00000000000..1becd8a92d6
--- /dev/null
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.fixed
@@ -0,0 +1,24 @@
+//@ run-rustfix
+//@ check-pass
+//@ compile-flags: --edition=2021
+#![allow(incomplete_features)]
+#![feature(expr_fragment_specifier_2024)]
+#![warn(edition_2024_expr_fragment_specifier)]
+
+macro_rules! m {
+    ($e:expr_2021) => { //~ WARN: the `expr` fragment specifier will accept more expressions in the 2024 edition
+       //~^ WARN: this changes meaning in Rust 2024
+        $e
+    };
+    ($($i:expr_2021)*) => { }; //~ WARN: the `expr` fragment specifier will accept more expressions in the 2024 edition
+       //~^ WARN: this changes meaning in Rust 2024
+}
+
+macro_rules! test {
+    (expr) => {}
+}
+
+fn main() {
+    m!(());
+    test!(expr);
+}
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.rs b/tests/ui/macros/expr_2021_cargo_fix_edition.rs
new file mode 100644
index 00000000000..ec0b86d2c23
--- /dev/null
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.rs
@@ -0,0 +1,24 @@
+//@ run-rustfix
+//@ check-pass
+//@ compile-flags: --edition=2021
+#![allow(incomplete_features)]
+#![feature(expr_fragment_specifier_2024)]
+#![warn(edition_2024_expr_fragment_specifier)]
+
+macro_rules! m {
+    ($e:expr) => { //~ WARN: the `expr` fragment specifier will accept more expressions in the 2024 edition
+       //~^ WARN: this changes meaning in Rust 2024
+        $e
+    };
+    ($($i:expr)*) => { }; //~ WARN: the `expr` fragment specifier will accept more expressions in the 2024 edition
+       //~^ WARN: this changes meaning in Rust 2024
+}
+
+macro_rules! test {
+    (expr) => {}
+}
+
+fn main() {
+    m!(());
+    test!(expr);
+}
diff --git a/tests/ui/macros/expr_2021_cargo_fix_edition.stderr b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
new file mode 100644
index 00000000000..e8a44fed322
--- /dev/null
+++ b/tests/ui/macros/expr_2021_cargo_fix_edition.stderr
@@ -0,0 +1,33 @@
+warning: the `expr` fragment specifier will accept more expressions in the 2024 edition
+  --> $DIR/expr_2021_cargo_fix_edition.rs:9:9
+   |
+LL |     ($e:expr) => {
+   |         ^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see Migration Guide <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html>
+note: the lint level is defined here
+  --> $DIR/expr_2021_cargo_fix_edition.rs:6:9
+   |
+LL | #![warn(edition_2024_expr_fragment_specifier)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to keep the existing behavior, use the `expr_2021` fragment specifier
+   |
+LL |     ($e:expr_2021) => {
+   |         ~~~~~~~~~
+
+warning: the `expr` fragment specifier will accept more expressions in the 2024 edition
+  --> $DIR/expr_2021_cargo_fix_edition.rs:13:11
+   |
+LL |     ($($i:expr)*) => { };
+   |           ^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see Migration Guide <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/macro-fragment-specifiers.html>
+help: to keep the existing behavior, use the `expr_2021` fragment specifier
+   |
+LL |     ($($i:expr_2021)*) => { };
+   |           ~~~~~~~~~
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
index 5e880964454..b55ae62030c 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `const`
-  --> $DIR/expr_2021_inline_const.rs:21:12
+  --> $DIR/expr_2021_inline_const.rs:26:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
@@ -14,7 +14,7 @@ LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
 
 error: no rules expected the token `const`
-  --> $DIR/expr_2021_inline_const.rs:22:12
+  --> $DIR/expr_2021_inline_const.rs:27:12
    |
 LL | macro_rules! m2024 {
    | ------------------ when calling this macro
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
index 237ecb2cc19..285db53d6c8 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `const`
-  --> $DIR/expr_2021_inline_const.rs:21:12
+  --> $DIR/expr_2021_inline_const.rs:26:12
    |
 LL | macro_rules! m2021 {
    | ------------------ when calling this macro
diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs
index ebc5ea36421..06b74a466d6 100644
--- a/tests/ui/macros/expr_2021_inline_const.rs
+++ b/tests/ui/macros/expr_2021_inline_const.rs
@@ -17,7 +17,14 @@ macro_rules! m2024 {
         $e
     };
 }
+
+macro_rules! test {
+    (expr) => {}
+}
+
 fn main() {
     m2021!(const { 1 }); //~ ERROR: no rules expected the token `const`
     m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const`
+
+    test!(expr);
 }
diff --git a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs
index e44eeffb01b..1acefa314aa 100644
--- a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs
+++ b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs
@@ -37,6 +37,16 @@ macro_rules! without_dollar_sign_is_an_ident {
     };
 }
 
+macro_rules! literals {
+    ($ident:ident) => {{
+        let ${concat(_a, "_b")}: () = ();
+        let ${concat("_b", _a)}: () = ();
+
+        let ${concat($ident, "_b")}: () = ();
+        let ${concat("_b", $ident)}: () = ();
+    }};
+}
+
 fn main() {
     create_things!(behold);
     behold_separated_idents_in_a_fn();
@@ -55,4 +65,6 @@ fn main() {
     without_dollar_sign_is_an_ident!(_123);
     assert_eq!(VARident, 1);
     assert_eq!(VAR_123, 2);
+
+    literals!(_hello);
 }
diff --git a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs
index f72b9baca89..b1cb2141cc4 100644
--- a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs
+++ b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs
@@ -26,14 +26,14 @@ macro_rules! idents_11 {
 macro_rules! no_params {
     () => {
         let ${concat(r#abc, abc)}: () = ();
-        //~^ ERROR `${concat(..)}` currently does not support raw identifiers
+        //~^ ERROR expected identifier or string literal
         //~| ERROR expected pattern, found `$`
 
         let ${concat(abc, r#abc)}: () = ();
-        //~^ ERROR `${concat(..)}` currently does not support raw identifiers
+        //~^ ERROR expected identifier or string literal
 
         let ${concat(r#abc, r#abc)}: () = ();
-        //~^ ERROR `${concat(..)}` currently does not support raw identifiers
+        //~^ ERROR expected identifier or string literal
     };
 }
 
diff --git a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr
index dd525cf0801..4e11e20acc5 100644
--- a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr
+++ b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr
@@ -1,16 +1,16 @@
-error: `${concat(..)}` currently does not support raw identifiers
+error: expected identifier or string literal
   --> $DIR/raw-identifiers.rs:28:22
    |
 LL |         let ${concat(r#abc, abc)}: () = ();
    |                      ^^^^^
 
-error: `${concat(..)}` currently does not support raw identifiers
+error: expected identifier or string literal
   --> $DIR/raw-identifiers.rs:32:27
    |
 LL |         let ${concat(abc, r#abc)}: () = ();
    |                           ^^^^^
 
-error: `${concat(..)}` currently does not support raw identifiers
+error: expected identifier or string literal
   --> $DIR/raw-identifiers.rs:35:22
    |
 LL |         let ${concat(r#abc, r#abc)}: () = ();
diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs
index bf47442ea76..b2845c8d1c1 100644
--- a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs
+++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs
@@ -11,9 +11,6 @@ macro_rules! wrong_concat_declarations {
         ${concat(aaaa,)}
         //~^ ERROR expected identifier
 
-        ${concat(aaaa, 1)}
-        //~^ ERROR expected identifier
-
         ${concat(_, aaaa)}
 
         ${concat(aaaa aaaa)}
@@ -30,9 +27,6 @@ macro_rules! wrong_concat_declarations {
 
         ${concat($ex, aaaa,)}
         //~^ ERROR expected identifier
-
-        ${concat($ex, aaaa, 123)}
-        //~^ ERROR expected identifier
     };
 }
 
@@ -43,8 +37,80 @@ macro_rules! dollar_sign_without_referenced_ident {
     };
 }
 
+macro_rules! starting_number {
+    ($ident:ident) => {{
+        let ${concat("1", $ident)}: () = ();
+        //~^ ERROR `${concat(..)}` is not generating a valid identifier
+    }};
+}
+
+macro_rules! starting_valid_unicode {
+    ($ident:ident) => {{
+        let ${concat("Ý", $ident)}: () = ();
+    }};
+}
+
+macro_rules! starting_invalid_unicode {
+    ($ident:ident) => {{
+        let ${concat("\u{00BD}", $ident)}: () = ();
+        //~^ ERROR `${concat(..)}` is not generating a valid identifier
+    }};
+}
+
+macro_rules! ending_number {
+    ($ident:ident) => {{
+        let ${concat($ident, "1")}: () = ();
+    }};
+}
+
+macro_rules! ending_valid_unicode {
+    ($ident:ident) => {{
+        let ${concat($ident, "Ý")}: () = ();
+    }};
+}
+
+macro_rules! ending_invalid_unicode {
+    ($ident:ident) => {{
+        let ${concat($ident, "\u{00BD}")}: () = ();
+        //~^ ERROR `${concat(..)}` is not generating a valid identifier
+    }};
+}
+
+macro_rules! empty {
+    () => {{
+        let ${concat("", "")}: () = ();
+        //~^ ERROR `${concat(..)}` is not generating a valid identifier
+    }};
+}
+
+macro_rules! unsupported_literals {
+    ($ident:ident) => {{
+        let ${concat(_a, 'b')}: () = ();
+        //~^ ERROR expected identifier or string literal
+        //~| ERROR expected pattern
+        let ${concat(_a, 1)}: () = ();
+        //~^ ERROR expected identifier or string literal
+
+        let ${concat($ident, 'b')}: () = ();
+        //~^ ERROR expected identifier or string literal
+        let ${concat($ident, 1)}: () = ();
+        //~^ ERROR expected identifier or string literal
+    }};
+}
+
 fn main() {
     wrong_concat_declarations!(1);
 
     dollar_sign_without_referenced_ident!(VAR);
+
+    starting_number!(_abc);
+    starting_valid_unicode!(_abc);
+    starting_invalid_unicode!(_abc);
+
+    ending_number!(_abc);
+    ending_valid_unicode!(_abc);
+    ending_invalid_unicode!(_abc);
+    unsupported_literals!(_abc);
+
+    empty!();
 }
diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr
index b216a86d59a..2fe5842b39e 100644
--- a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr
+++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr
@@ -1,4 +1,4 @@
-error: expected identifier
+error: expected identifier or string literal
   --> $DIR/syntax-errors.rs:5:10
    |
 LL |         ${concat()}
@@ -10,59 +10,126 @@ error: `concat` must have at least two elements
 LL |         ${concat(aaaa)}
    |           ^^^^^^
 
-error: expected identifier
+error: expected identifier or string literal
   --> $DIR/syntax-errors.rs:11:10
    |
 LL |         ${concat(aaaa,)}
    |          ^^^^^^^^^^^^^^^
 
-error: expected identifier, found `1`
-  --> $DIR/syntax-errors.rs:14:24
-   |
-LL |         ${concat(aaaa, 1)}
-   |                        ^ help: try removing `1`
-
 error: expected comma
-  --> $DIR/syntax-errors.rs:19:10
+  --> $DIR/syntax-errors.rs:16:10
    |
 LL |         ${concat(aaaa aaaa)}
    |          ^^^^^^^^^^^^^^^^^^^
 
 error: `concat` must have at least two elements
-  --> $DIR/syntax-errors.rs:22:11
+  --> $DIR/syntax-errors.rs:19:11
    |
 LL |         ${concat($ex)}
    |           ^^^^^^
 
 error: expected comma
-  --> $DIR/syntax-errors.rs:28:10
+  --> $DIR/syntax-errors.rs:25:10
    |
 LL |         ${concat($ex, aaaa 123)}
    |          ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: expected identifier
-  --> $DIR/syntax-errors.rs:31:10
+error: expected identifier or string literal
+  --> $DIR/syntax-errors.rs:28:10
    |
 LL |         ${concat($ex, aaaa,)}
    |          ^^^^^^^^^^^^^^^^^^^^
 
-error: expected identifier, found `123`
-  --> $DIR/syntax-errors.rs:34:29
+error: expected identifier or string literal
+  --> $DIR/syntax-errors.rs:88:26
    |
-LL |         ${concat($ex, aaaa, 123)}
-   |                             ^^^ help: try removing `123`
+LL |         let ${concat(_a, 'b')}: () = ();
+   |                          ^^^
+
+error: expected identifier or string literal
+  --> $DIR/syntax-errors.rs:91:26
+   |
+LL |         let ${concat(_a, 1)}: () = ();
+   |                          ^
+
+error: expected identifier or string literal
+  --> $DIR/syntax-errors.rs:94:30
+   |
+LL |         let ${concat($ident, 'b')}: () = ();
+   |                              ^^^
+
+error: expected identifier or string literal
+  --> $DIR/syntax-errors.rs:96:30
+   |
+LL |         let ${concat($ident, 1)}: () = ();
+   |                              ^
 
 error: `${concat(..)}` currently only accepts identifiers or meta-variables as parameters
-  --> $DIR/syntax-errors.rs:25:19
+  --> $DIR/syntax-errors.rs:22:19
    |
 LL |         ${concat($ex, aaaa)}
    |                   ^^
 
 error: variable `foo` is not recognized in meta-variable expression
-  --> $DIR/syntax-errors.rs:41:30
+  --> $DIR/syntax-errors.rs:35:30
    |
 LL |         const ${concat(FOO, $foo)}: i32 = 2;
    |                              ^^^
 
-error: aborting due to 11 previous errors
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:42:14
+   |
+LL |         let ${concat("1", $ident)}: () = ();
+   |              ^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     starting_number!(_abc);
+   |     ---------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `starting_number` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:55:14
+   |
+LL |         let ${concat("\u{00BD}", $ident)}: () = ();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     starting_invalid_unicode!(_abc);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `starting_invalid_unicode` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:74:14
+   |
+LL |         let ${concat($ident, "\u{00BD}")}: () = ();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     ending_invalid_unicode!(_abc);
+   |     ----------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `ending_invalid_unicode` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected pattern, found `$`
+  --> $DIR/syntax-errors.rs:88:13
+   |
+LL |         let ${concat(_a, 'b')}: () = ();
+   |             ^ expected pattern
+...
+LL |     unsupported_literals!(_abc);
+   |     --------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `unsupported_literals` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:81:14
+   |
+LL |         let ${concat("", "")}: () = ();
+   |              ^^^^^^^^^^^^^^^^
+...
+LL |     empty!();
+   |     -------- in this macro invocation
+   |
+   = note: this error originates in the macro `empty` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 18 previous errors
 
diff --git a/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs b/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs
new file mode 100644
index 00000000000..b2cfb211e2d
--- /dev/null
+++ b/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs
@@ -0,0 +1,14 @@
+//@ run-pass
+
+#![feature(macro_metavar_expr_concat)]
+
+macro_rules! turn_to_page {
+    ($ident:ident) => {
+        const ${concat("Ḧ", $ident)}: i32 = 394;
+    };
+}
+
+fn main() {
+    turn_to_page!(P);
+    assert_eq!(ḦP, 394);
+}
diff --git a/tests/ui/macros/out-of-scope-calls-false-positives.rs b/tests/ui/macros/out-of-scope-calls-false-positives.rs
new file mode 100644
index 00000000000..8d696c177e4
--- /dev/null
+++ b/tests/ui/macros/out-of-scope-calls-false-positives.rs
@@ -0,0 +1,10 @@
+//@ check-pass
+//@ needs-asm-support
+
+macro_rules! mac { () => { "" } }
+macro_rules! mac2 { () => { "auxiliary/issue-40469.rs" } }
+
+std::arch::global_asm!(mac!()); // OK
+include!(mac2!()); // OK
+
+fn main() {}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
index 8e4ba192d79..2c44ad2e0a4 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
@@ -190,7 +190,7 @@ error: unrecognized meta-variable expression
 LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
    |                                 ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and len
 
-error: expected identifier
+error: expected identifier or string literal
   --> $DIR/syntax-errors.rs:118:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ {} } };
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
index 83f1ee6a77e..7cbe8e0943a 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
@@ -1,5 +1,6 @@
 //@ edition: 2024
 //@ compile-flags: -Zunstable-options
+// gate-test-ref_pat_eat_one_layer_2024_structural
 
 pub fn main() {
     if let Some(Some(&x)) = &Some(&Some(0)) {
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
index 132fe421a18..b3ea60252ac 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:5:22
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:6:22
    |
 LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
    |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -14,7 +14,7 @@ LL |     if let Some(Some(x)) = &Some(&Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:10:23
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:11:23
    |
 LL |         let _: &u32 = x;
    |                ----   ^ expected `&u32`, found integer
@@ -27,7 +27,7 @@ LL |         let _: &u32 = &x;
    |                       +
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:13:23
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:14:23
    |
 LL |     if let Some(Some(&&x)) = &Some(Some(&0)) {
    |                       ^^     --------------- this expression has type `&Option<Option<&{integer}>>`
@@ -43,7 +43,7 @@ LL +     if let Some(Some(&x)) = &Some(Some(&0)) {
    |
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:17:17
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:18:17
    |
 LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
@@ -54,7 +54,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
            found reference `&_`
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:22:22
    |
 LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    |                      ^^^^^^     ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
@@ -64,7 +64,7 @@ LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    = note:           expected type `{integer}`
            found mutable reference `&mut _`
 note: to declare a mutable binding use: `mut x`
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:22:22
    |
 LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    |                      ^^^^^^
@@ -74,7 +74,7 @@ LL |     if let Some(Some(x)) = &mut Some(&mut Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:25:22
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:26:22
    |
 LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
    |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -89,7 +89,7 @@ LL |     if let Some(Some(x)) = &Some(&Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:29:27
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:30:27
    |
 LL |     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
    |                           ^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
@@ -104,7 +104,7 @@ LL |     if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
    |                           ~
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:34:23
    |
 LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
    |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
@@ -114,7 +114,7 @@ LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
    = note:           expected type `{integer}`
            found mutable reference `&mut _`
 note: to declare a mutable binding use: `mut x`
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:34:23
    |
 LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
    |                       ^^^^^^
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs
index d28567f2859..afea249ffef 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs
@@ -1,37 +1,15 @@
+//@ run-pass
 //@ edition: 2021
+//@ revisions: classic structural both
 #![allow(incomplete_features)]
-#![feature(ref_pat_eat_one_layer_2024)]
+#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))]
+
 pub fn main() {
-    if let Some(Some(&x)) = &Some(&Some(0)) {
-        //~^ ERROR: mismatched types
-        let _: u32 = x;
-    }
-    if let Some(Some(&x)) = &Some(Some(&0)) {
+    if let &Some(Some(x)) = &Some(&mut Some(0)) {
         let _: &u32 = x;
-        //~^ ERROR: mismatched types
-    }
-    if let Some(Some(&&x)) = &Some(Some(&0)) {
-        //~^ ERROR: mismatched types
-        let _: u32 = x;
-    }
-    if let Some(&Some(x)) = &Some(Some(0)) {
-        //~^ ERROR: mismatched types
-        let _: u32 = x;
-    }
-    if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
-        //~^ ERROR: mismatched types
-        let _: u32 = x;
-    }
-    if let Some(Some(&x)) = &Some(&Some(0)) {
-        //~^ ERROR: mismatched types
-        let _: u32 = x;
-    }
-    if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
-        //~^ ERROR: mismatched types
-        let _: u32 = x;
     }
-    if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
-        //~^ ERROR: mismatched types
+    if let Some(&x) = Some(&mut 0) {
         let _: u32 = x;
     }
 }
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs
new file mode 100644
index 00000000000..d28567f2859
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs
@@ -0,0 +1,37 @@
+//@ edition: 2021
+#![allow(incomplete_features)]
+#![feature(ref_pat_eat_one_layer_2024)]
+pub fn main() {
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&x)) = &Some(Some(&0)) {
+        let _: &u32 = x;
+        //~^ ERROR: mismatched types
+    }
+    if let Some(Some(&&x)) = &Some(Some(&0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(&Some(x)) = &Some(Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+    if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
+        //~^ ERROR: mismatched types
+        let _: u32 = x;
+    }
+}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr
index 28706f89c06..1a921234ea0 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:5:22
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:5:22
    |
 LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
    |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -14,7 +14,7 @@ LL |     if let Some(Some(x)) = &Some(&Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:10:23
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:10:23
    |
 LL |         let _: &u32 = x;
    |                ----   ^ expected `&u32`, found integer
@@ -27,7 +27,7 @@ LL |         let _: &u32 = &x;
    |                       +
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:13:23
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:13:23
    |
 LL |     if let Some(Some(&&x)) = &Some(Some(&0)) {
    |                       ^^     --------------- this expression has type `&Option<Option<&{integer}>>`
@@ -43,7 +43,7 @@ LL +     if let Some(Some(&x)) = &Some(Some(&0)) {
    |
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:17:17
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:17:17
    |
 LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
@@ -54,7 +54,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
            found reference `&_`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:21:22
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:21:22
    |
 LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    |                      ^^^^^^     ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
@@ -64,7 +64,7 @@ LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    = note:           expected type `{integer}`
            found mutable reference `&mut _`
 note: to declare a mutable binding use: `mut x`
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:21:22
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:21:22
    |
 LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    |                      ^^^^^^
@@ -74,7 +74,7 @@ LL |     if let Some(Some(x)) = &mut Some(&mut Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:25:22
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:25:22
    |
 LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
    |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -89,7 +89,7 @@ LL |     if let Some(Some(x)) = &Some(&Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:29:27
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:29:27
    |
 LL |     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
    |                           ^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
@@ -104,7 +104,7 @@ LL |     if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
    |                           ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:33:23
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:33:23
    |
 LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
    |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
@@ -114,7 +114,7 @@ LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
    = note:           expected type `{integer}`
            found mutable reference `&mut _`
 note: to declare a mutable binding use: `mut x`
-  --> $DIR/ref_pat_eat_one_layer_2021.rs:33:23
+  --> $DIR/ref_pat_eat_one_layer_2021_fail.rs:33:23
    |
 LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
    |                       ^^^^^^
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
index 829b7f86e26..c6a699d2ff8 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
@@ -1,8 +1,10 @@
 //@ run-pass
 //@ edition: 2024
 //@ compile-flags: -Zunstable-options
+//@ revisions: classic structural both
 #![allow(incomplete_features)]
-#![feature(ref_pat_eat_one_layer_2024)]
+#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     if let Some(Some(&x)) = &Some(&Some(0)) {
@@ -53,4 +55,35 @@ pub fn main() {
     if let Some(&Some(x)) = &mut Some(Some(0)) {
         let _: u32 = x;
     }
+    #[cfg(any(classic, both))]
+    if let Some(&mut x) = &mut Some(&0) {
+        let _: &u32 = x;
+    }
+    #[cfg(any(structural, both))]
+    if let Some(&mut x) = &Some(&mut 0) {
+        let _: &u32 = x;
+    }
+
+    fn generic<R: Ref>() -> (R, bool) {
+        R::meow()
+    }
+
+    trait Ref: Sized {
+        fn meow() -> (Self, bool);
+    }
+
+    impl Ref for &'static [(); 0] {
+        fn meow() -> (Self, bool) {
+            (&[], false)
+        }
+    }
+
+    impl Ref for &'static mut [(); 0] {
+        fn meow() -> (Self, bool) {
+            (&mut [], true)
+        }
+    }
+
+    let (&_, b) = generic();
+    assert!(!b);
 }
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr
new file mode 100644
index 00000000000..0215df98ea1
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr
@@ -0,0 +1,169 @@
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:9: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/ref_pat_eat_one_layer_2024_fail.rs:12: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/ref_pat_eat_one_layer_2024_fail.rs:16:27
+   |
+LL |         let _: &mut u32 = x;
+   |                --------   ^ types differ in mutability
+   |                |
+   |                expected due to this
+   |
+   = note: expected mutable reference `&mut u32`
+                      found reference `&{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:19: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/ref_pat_eat_one_layer_2024_fail.rs:22: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/ref_pat_eat_one_layer_2024_fail.rs:25: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/ref_pat_eat_one_layer_2024_fail.rs:28: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/ref_pat_eat_one_layer_2024_fail.rs:32:9
+   |
+LL |     let &mut _ = &&0;
+   |         ^^^^^^   --- this expression has type `&&{integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:35:9
+   |
+LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
+   |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:46:9
+   |
+LL |     let &mut _ = &&mut 0;
+   |         ^^^^^^   ------- this expression has type `&&mut {integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:49:9
+   |
+LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
+   |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:52:14
+   |
+LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
+   |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
+   |              |
+   |              types differ in mutability
+   |
+   = note:      expected reference `&&&&mut &&&mut &mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0658]: binding cannot be both mutable and by-reference
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:61:13
+   |
+LL |     let Foo(mut a) = &Foo(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/ref_pat_eat_one_layer_2024_fail.rs:65:13
+   |
+LL |     let Foo(mut a) = &mut Foo(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[E0277]: the trait bound `&_: main::Ref` is not satisfied
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:83:14
+   |
+LL |     let &_ = generic();
+   |              ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
+   |
+   = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
+note: required by a bound in `generic`
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:69:19
+   |
+LL |     fn generic<R: Ref>() -> R {
+   |                   ^^^ required by this bound in `generic`
+
+error: aborting due to 15 previous errors
+
+Some errors have detailed explanations: E0277, E0308, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr
index 26317e43d02..9428b32c4af 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr
@@ -1,27 +1,29 @@
-error: cannot match inherited `&` with `&mut` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:7:17
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:9: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: cannot match inherited `&` with `&mut` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:10:23
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:12: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/ref_pat_eat_one_layer_2024_fail.rs:14:27
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:16:27
    |
 LL |         let _: &mut u32 = x;
    |                --------   ^ types differ in mutability
@@ -31,52 +33,56 @@ LL |         let _: &mut u32 = x;
    = note: expected mutable reference `&mut u32`
                       found reference `&{integer}`
 
-error: cannot match inherited `&` with `&mut` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:17:23
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:19: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: cannot match inherited `&` with `&mut` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:29
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:22:29
    |
 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: cannot match inherited `&` with `&mut` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:17
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:25: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: cannot match inherited `&` with `&mut` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:17
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28: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/ref_pat_eat_one_layer_2024_fail.rs:30:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:9
    |
 LL |     let &mut _ = &&0;
    |         ^^^^^^   --- this expression has type `&&{integer}`
@@ -87,7 +93,7 @@ LL |     let &mut _ = &&0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:33:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:35:9
    |
 LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
    |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
@@ -97,30 +103,32 @@ LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
    = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
            found mutable reference `&mut _`
 
-error: cannot match inherited `&` with `&mut` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:36:17
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:38:17
    |
 LL |     if let 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(&mut Some(0)) {
    |                 ~
 
-error: cannot match inherited `&` with `&mut` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:40:22
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:42:22
    |
 LL |     if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
    |                      ^^^^^
    |
+   = note: cannot match inherited `&` with `&mut` pattern
 help: replace this `&mut` pattern with `&`
    |
 LL |     if let Some(Some(&x)) = &Some(Some(&mut 0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:44:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:46:9
    |
 LL |     let &mut _ = &&mut 0;
    |         ^^^^^^   ------- this expression has type `&&mut {integer}`
@@ -131,7 +139,7 @@ LL |     let &mut _ = &&mut 0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:47:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:49:9
    |
 LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
    |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
@@ -142,7 +150,7 @@ LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:50:14
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:52:14
    |
 LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
    |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
@@ -153,7 +161,7 @@ LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
            found mutable reference `&mut _`
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:55:13
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:61:13
    |
 LL |     let Foo(mut a) = &Foo(0);
    |             ^^^^
@@ -163,7 +171,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/ref_pat_eat_one_layer_2024_fail.rs:59:13
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:65:13
    |
 LL |     let Foo(mut a) = &mut Foo(0);
    |             ^^^^
@@ -172,7 +180,20 @@ 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 16 previous errors
+error[E0277]: the trait bound `&_: main::Ref` is not satisfied
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:83:14
+   |
+LL |     let &_ = generic();
+   |              ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
+   |
+   = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
+note: required by a bound in `generic`
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:69:19
+   |
+LL |     fn generic<R: Ref>() -> R {
+   |                   ^^^ required by this bound in `generic`
+
+error: aborting due to 17 previous errors
 
-Some errors have detailed explanations: E0308, E0658.
-For more information about an error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0277, E0308, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
index 40e8293e241..d23e9c8083d 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
@@ -1,30 +1,32 @@
 //@ edition: 2024
 //@ compile-flags: -Zunstable-options
+//@ revisions: classic structural both
 #![allow(incomplete_features)]
-#![feature(ref_pat_eat_one_layer_2024)]
+#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))]
+#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))]
 
 pub fn main() {
     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
-        //~^ ERROR: cannot match inherited `&` with `&mut` pattern
+        //~^ ERROR: mismatched types
     }
     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
-        //~^ ERROR: cannot match inherited `&` with `&mut` pattern
+        //~^ ERROR: mismatched types
     }
     if let Some(&Some(x)) = &mut Some(&Some(0)) {
         let _: &mut u32 = x;
         //~^ ERROR: mismatched types
     }
     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
-        //~^ ERROR: cannot match inherited `&` with `&mut` pattern
+        //~^ ERROR: mismatched types
     }
     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
-        //~^ ERROR: cannot match inherited `&` with `&mut` pattern
+        //~^ ERROR: mismatched types
     }
     if let Some(&mut Some(x)) = &Some(Some(0)) {
-        //~^ ERROR: cannot match inherited `&` with `&mut` pattern
+        //~^ ERROR: mismatched types
     }
     if let Some(&mut Some(x)) = &Some(Some(0)) {
-        //~^ ERROR: cannot match inherited `&` with `&mut` pattern
+        //~^ ERROR: mismatched types
     }
 
     let &mut _ = &&0;
@@ -34,11 +36,11 @@ pub fn main() {
     //~^ ERROR: mismatched types
 
     if let Some(&mut Some(&_)) = &Some(&mut Some(0)) {
-        //~^ ERROR: cannot match inherited `&` with `&mut` pattern
+        //[classic]~^ ERROR: mismatched types
     }
 
     if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
-        //~^ ERROR: cannot match inherited `&` with `&mut` pattern
+        //[classic]~^ ERROR: mismatched types
     }
 
     let &mut _ = &&mut 0;
@@ -50,6 +52,10 @@ pub fn main() {
     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
     //~^ ERROR: mismatched types
 
+    if let Some(&mut _) = &mut Some(&0) {
+        //[structural]~^ ERROR
+    }
+
     struct Foo(u8);
 
     let Foo(mut a) = &Foo(0);
@@ -59,4 +65,20 @@ pub fn main() {
     let Foo(mut a) = &mut Foo(0);
     //~^ ERROR: binding cannot be both mutable and by-reference
     a = &mut 42;
+
+    fn generic<R: Ref>() -> R {
+        R::meow()
+    }
+
+    trait Ref: Sized {
+        fn meow() -> Self;
+    }
+
+    impl Ref for &'static mut [(); 0] {
+        fn meow() -> Self {
+            &mut []
+        }
+    }
+
+    let &_ = generic(); //~ERROR: the trait bound `&_: main::Ref` is not satisfied [E0277]
 }
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr
new file mode 100644
index 00000000000..56dad605030
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr
@@ -0,0 +1,180 @@
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:9: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/ref_pat_eat_one_layer_2024_fail.rs:12: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/ref_pat_eat_one_layer_2024_fail.rs:16:27
+   |
+LL |         let _: &mut u32 = x;
+   |                --------   ^ types differ in mutability
+   |                |
+   |                expected due to this
+   |
+   = note: expected mutable reference `&mut u32`
+                      found reference `&{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:19: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/ref_pat_eat_one_layer_2024_fail.rs:22: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/ref_pat_eat_one_layer_2024_fail.rs:25: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/ref_pat_eat_one_layer_2024_fail.rs:28: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/ref_pat_eat_one_layer_2024_fail.rs:32:9
+   |
+LL |     let &mut _ = &&0;
+   |         ^^^^^^   --- this expression has type `&&{integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:35:9
+   |
+LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
+   |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:46:9
+   |
+LL |     let &mut _ = &&mut 0;
+   |         ^^^^^^   ------- this expression has type `&&mut {integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:49:9
+   |
+LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
+   |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
+   |         |
+   |         types differ in mutability
+   |
+   = note:      expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:52:14
+   |
+LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
+   |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
+   |              |
+   |              types differ in mutability
+   |
+   = note:      expected reference `&&&&mut &&&mut &mut {integer}`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:55:17
+   |
+LL |     if let Some(&mut _) = &mut Some(&0) {
+   |                 ^^^^^^    ------------- this expression has type `&mut Option<&{integer}>`
+   |                 |
+   |                 types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+
+error[E0658]: binding cannot be both mutable and by-reference
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:61:13
+   |
+LL |     let Foo(mut a) = &Foo(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/ref_pat_eat_one_layer_2024_fail.rs:65:13
+   |
+LL |     let Foo(mut a) = &mut Foo(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[E0277]: the trait bound `&_: main::Ref` is not satisfied
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:83:14
+   |
+LL |     let &_ = generic();
+   |              ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
+   |
+   = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
+note: required by a bound in `generic`
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:69:19
+   |
+LL |     fn generic<R: Ref>() -> R {
+   |                   ^^^ required by this bound in `generic`
+
+error: aborting due to 16 previous errors
+
+Some errors have detailed explanations: E0277, E0308, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/method-output-diff-issue-127263.rs b/tests/ui/method-output-diff-issue-127263.rs
new file mode 100644
index 00000000000..85a903e2453
--- /dev/null
+++ b/tests/ui/method-output-diff-issue-127263.rs
@@ -0,0 +1,8 @@
+fn bar() {}
+fn foo(x: i32) -> u32 {
+    0
+}
+fn main() {
+    let b: fn() -> u32 = bar; //~ ERROR mismatched types [E0308]
+    let f: fn(i32) = foo; //~ ERROR mismatched types [E0308]
+}
diff --git a/tests/ui/method-output-diff-issue-127263.stderr b/tests/ui/method-output-diff-issue-127263.stderr
new file mode 100644
index 00000000000..35b86114f16
--- /dev/null
+++ b/tests/ui/method-output-diff-issue-127263.stderr
@@ -0,0 +1,25 @@
+error[E0308]: mismatched types
+  --> $DIR/method-output-diff-issue-127263.rs:6:26
+   |
+LL |     let b: fn() -> u32 = bar;
+   |            -----------   ^^^ expected fn pointer, found fn item
+   |            |
+   |            expected due to this
+   |
+   = note: expected fn pointer `fn() -> u32`
+                 found fn item `fn() -> () {bar}`
+
+error[E0308]: mismatched types
+  --> $DIR/method-output-diff-issue-127263.rs:7:22
+   |
+LL |     let f: fn(i32) = foo;
+   |            -------   ^^^ expected fn pointer, found fn item
+   |            |
+   |            expected due to this
+   |
+   = note: expected fn pointer `fn(_) -> ()`
+                 found fn item `fn(_) -> u32 {foo}`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr
index 5a76449e9f9..0855a17b333 100644
--- a/tests/ui/methods/method-call-err-msg.stderr
+++ b/tests/ui/methods/method-call-err-msg.stderr
@@ -2,16 +2,18 @@ error[E0061]: this method takes 0 arguments but 1 argument was supplied
   --> $DIR/method-call-err-msg.rs:13:7
    |
 LL |     x.zero(0)
-   |       ^^^^ -
-   |            |
-   |            unexpected argument of type `{integer}`
-   |            help: remove the extra argument
+   |       ^^^^ - unexpected argument of type `{integer}`
    |
 note: method defined here
   --> $DIR/method-call-err-msg.rs:5:8
    |
 LL |     fn zero(self) -> Foo { self }
    |        ^^^^
+help: remove the extra argument
+   |
+LL -     x.zero(0)
+LL +     x.zero()
+   |
 
 error[E0061]: this method takes 1 argument but 0 arguments were supplied
   --> $DIR/method-call-err-msg.rs:14:7
diff --git a/tests/ui/mir/alignment/misaligned-constant-gvn.rs b/tests/ui/mir/alignment/misaligned-constant-gvn.rs
new file mode 100644
index 00000000000..363d5c0ed34
--- /dev/null
+++ b/tests/ui/mir/alignment/misaligned-constant-gvn.rs
@@ -0,0 +1,8 @@
+//@ build-pass
+//@ compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=+GVN
+
+fn main() {
+    let variant: Option<u32> = None;
+    let transmuted: u64 = unsafe { std::mem::transmute(variant) };
+    println!("{transmuted}");
+}
diff --git a/tests/ui/mismatched_types/E0053.stderr b/tests/ui/mismatched_types/E0053.stderr
index d0bd5b46cf5..2559d448749 100644
--- a/tests/ui/mismatched_types/E0053.stderr
+++ b/tests/ui/mismatched_types/E0053.stderr
@@ -2,10 +2,7 @@ error[E0053]: method `foo` has an incompatible type for trait
   --> $DIR/E0053.rs:9:15
    |
 LL |     fn foo(x: i16) { }
-   |               ^^^
-   |               |
-   |               expected `u16`, found `i16`
-   |               help: change the parameter type to match the trait: `u16`
+   |               ^^^ expected `u16`, found `i16`
    |
 note: type in trait
   --> $DIR/E0053.rs:2:15
@@ -14,15 +11,16 @@ LL |     fn foo(x: u16);
    |               ^^^
    = note: expected signature `fn(u16)`
               found signature `fn(i16)`
+help: change the parameter type to match the trait
+   |
+LL |     fn foo(x: u16) { }
+   |               ~~~
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/E0053.rs:11:12
    |
 LL |     fn bar(&mut self) { }
-   |            ^^^^^^^^^
-   |            |
-   |            types differ in mutability
-   |            help: change the self-receiver type to match the trait: `&self`
+   |            ^^^^^^^^^ types differ in mutability
    |
 note: type in trait
   --> $DIR/E0053.rs:3:12
@@ -31,6 +29,10 @@ LL |     fn bar(&self);
    |            ^^^^^
    = note: expected signature `fn(&Bar)`
               found signature `fn(&mut Bar)`
+help: change the self-receiver type to match the trait
+   |
+LL |     fn bar(&self) { }
+   |            ~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/mismatched_types/cast-rfc0401.rs b/tests/ui/mismatched_types/cast-rfc0401.rs
index 57222f45947..b2ff5b4a0c0 100644
--- a/tests/ui/mismatched_types/cast-rfc0401.rs
+++ b/tests/ui/mismatched_types/cast-rfc0401.rs
@@ -66,7 +66,7 @@ fn main()
 
     let cf: *const dyn Foo = &0;
     let _ = cf as *const [u16]; //~ ERROR is invalid
-    let _ = cf as *const dyn Bar; //~ ERROR is invalid
+    let _ = cf as *const dyn Bar; //~ ERROR casting `*const dyn Foo` as `*const dyn Bar` is invalid
 
     vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>(); //~ ERROR is invalid
 }
diff --git a/tests/ui/mismatched_types/float-literal-inference-restrictions.stderr b/tests/ui/mismatched_types/float-literal-inference-restrictions.stderr
index 454373c322e..6b3e0cb505f 100644
--- a/tests/ui/mismatched_types/float-literal-inference-restrictions.stderr
+++ b/tests/ui/mismatched_types/float-literal-inference-restrictions.stderr
@@ -2,11 +2,14 @@ error[E0308]: mismatched types
   --> $DIR/float-literal-inference-restrictions.rs:2:18
    |
 LL |     let x: f32 = 1;
-   |            ---   ^
-   |            |     |
-   |            |     expected `f32`, found integer
-   |            |     help: use a float literal: `1.0`
+   |            ---   ^ expected `f32`, found integer
+   |            |
    |            expected due to this
+   |
+help: use a float literal
+   |
+LL |     let x: f32 = 1.0;
+   |                   ++
 
 error[E0308]: mismatched types
   --> $DIR/float-literal-inference-restrictions.rs:3:18
diff --git a/tests/ui/mismatched_types/issue-112036.stderr b/tests/ui/mismatched_types/issue-112036.stderr
index b93ce4a8674..bd446b3d78c 100644
--- a/tests/ui/mismatched_types/issue-112036.stderr
+++ b/tests/ui/mismatched_types/issue-112036.stderr
@@ -2,13 +2,14 @@ error[E0053]: method `drop` has an incompatible type for trait
   --> $DIR/issue-112036.rs:4:13
    |
 LL |     fn drop(self) {}
-   |             ^^^^
-   |             |
-   |             expected `&mut Foo`, found `Foo`
-   |             help: change the self-receiver type to match the trait: `&mut self`
+   |             ^^^^ expected `&mut Foo`, found `Foo`
    |
    = note: expected signature `fn(&mut Foo)`
               found signature `fn(Foo)`
+help: change the self-receiver type to match the trait
+   |
+LL |     fn drop(&mut self) {}
+   |             ~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/mismatched_types/issue-13033.stderr b/tests/ui/mismatched_types/issue-13033.stderr
index 4886fa30e89..2a266d40e77 100644
--- a/tests/ui/mismatched_types/issue-13033.stderr
+++ b/tests/ui/mismatched_types/issue-13033.stderr
@@ -2,10 +2,7 @@ error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/issue-13033.rs:8:30
    |
 LL |     fn bar(&mut self, other: &dyn Foo) {}
-   |                              ^^^^^^^^
-   |                              |
-   |                              types differ in mutability
-   |                              help: change the parameter type to match the trait: `&mut dyn Foo`
+   |                              ^^^^^^^^ types differ in mutability
    |
 note: type in trait
   --> $DIR/issue-13033.rs:2:30
@@ -14,6 +11,10 @@ LL |     fn bar(&mut self, other: &mut dyn Foo);
    |                              ^^^^^^^^^^^^
    = note: expected signature `fn(&mut Baz, &mut dyn Foo)`
               found signature `fn(&mut Baz, &dyn Foo)`
+help: change the parameter type to match the trait
+   |
+LL |     fn bar(&mut self, other: &mut dyn Foo) {}
+   |                              ~~~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/tests/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
index 6e7bf5eb46d..2e544a62223 100644
--- a/tests/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
+++ b/tests/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
@@ -2,10 +2,7 @@ error[E0053]: method `foo` has an incompatible type for trait
   --> $DIR/trait-impl-fn-incompatibility.rs:9:15
    |
 LL |     fn foo(x: i16) { }
-   |               ^^^
-   |               |
-   |               expected `u16`, found `i16`
-   |               help: change the parameter type to match the trait: `u16`
+   |               ^^^ expected `u16`, found `i16`
    |
 note: type in trait
   --> $DIR/trait-impl-fn-incompatibility.rs:2:15
@@ -14,15 +11,16 @@ LL |     fn foo(x: u16);
    |               ^^^
    = note: expected signature `fn(u16)`
               found signature `fn(i16)`
+help: change the parameter type to match the trait
+   |
+LL |     fn foo(x: u16) { }
+   |               ~~~
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/trait-impl-fn-incompatibility.rs:10:28
    |
 LL |     fn bar(&mut self, bar: &Bar) { }
-   |                            ^^^^
-   |                            |
-   |                            types differ in mutability
-   |                            help: change the parameter type to match the trait: `&mut Bar`
+   |                            ^^^^ types differ in mutability
    |
 note: type in trait
   --> $DIR/trait-impl-fn-incompatibility.rs:3:28
@@ -31,6 +29,10 @@ LL |     fn bar(&mut self, bar: &mut Bar);
    |                            ^^^^^^^^
    = note: expected signature `fn(&mut Bar, &mut Bar)`
               found signature `fn(&mut Bar, &Bar)`
+help: change the parameter type to match the trait
+   |
+LL |     fn bar(&mut self, bar: &mut Bar) { }
+   |                            ~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/msvc-opt-minsize.rs b/tests/ui/msvc-opt-minsize.rs
new file mode 100644
index 00000000000..c1be168a05d
--- /dev/null
+++ b/tests/ui/msvc-opt-minsize.rs
@@ -0,0 +1,31 @@
+// A previously outdated version of LLVM caused compilation failures on Windows
+// specifically with optimization level `z`. After the update to a more recent LLVM
+// version, this test checks that compilation and execution both succeed.
+// See https://github.com/rust-lang/rust/issues/45034
+
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+//@ only-windows
+// Reason: the observed bug only occurs on Windows
+//@ run-pass
+//@ compile-flags: -C opt-level=z
+
+#![feature(test)]
+extern crate test;
+
+fn foo(x: i32, y: i32) -> i64 {
+    (x + y) as i64
+}
+
+#[inline(never)]
+fn bar() {
+    let _f = Box::new(0);
+    // This call used to trigger an LLVM bug in opt-level z where the base
+    // pointer gets corrupted, see issue #45034
+    let y: fn(i32, i32) -> i64 = test::black_box(foo);
+    test::black_box(y(1, 2));
+}
+
+fn main() {
+    bar();
+}
diff --git a/tests/ui/mut/mut-pattern-internal-mutability.stderr b/tests/ui/mut/mut-pattern-internal-mutability.stderr
index ab80af17a08..f3a8aa0126c 100644
--- a/tests/ui/mut/mut-pattern-internal-mutability.stderr
+++ b/tests/ui/mut/mut-pattern-internal-mutability.stderr
@@ -9,11 +9,11 @@ LL |     x += 1;
 help: consider making this binding mutable
    |
 LL |     let &mut mut x = foo;
-   |              ~~~~~
+   |              +++
 help: to modify the original value, take a borrow instead
    |
 LL |     let &mut ref mut x = foo;
-   |              ~~~~~~~~~
+   |              +++++++
 
 error[E0506]: cannot assign to `*foo` because it is borrowed
   --> $DIR/mut-pattern-internal-mutability.rs:13:5
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
index fbd92f8f662..a75039b8237 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr
@@ -1,5 +1,5 @@
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:8:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:13:18
    |
 LL |         unsafe { mem::zeroed() }
    |                  ^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |         unsafe { mem::zeroed() }
    = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:23:13
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:30:13
    |
 LL |             core::mem::transmute(Zst)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |             core::mem::transmute(Zst)
    = help: specify the type explicitly
 
 warning: never type fallback affects this union access
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:39:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:47:18
    |
 LL |         unsafe { Union { a: () }.b }
    |                  ^^^^^^^^^^^^^^^^^
@@ -30,7 +30,7 @@ LL |         unsafe { Union { a: () }.b }
    = help: specify the type explicitly
 
 warning: never type fallback affects this raw pointer dereference
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:49:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:58:18
    |
 LL |         unsafe { *ptr::from_ref(&()).cast() }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL |         unsafe { *ptr::from_ref(&()).cast() }
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:67:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:18
    |
 LL |         unsafe { internally_create(x) }
    |                  ^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL |         unsafe { internally_create(x) }
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:83:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:97:18
    |
 LL |         unsafe { zeroed() }
    |                  ^^^^^^^^
@@ -60,7 +60,7 @@ LL |         unsafe { zeroed() }
    = help: specify the type explicitly
 
 warning: never type fallback affects this `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:22
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:92:22
    |
 LL |         let zeroed = mem::zeroed;
    |                      ^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL |         let zeroed = mem::zeroed;
    = help: specify the type explicitly
 
 warning: never type fallback affects this `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:98:17
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:115:17
    |
 LL |         let f = internally_create;
    |                 ^^^^^^^^^^^^^^^^^
@@ -80,7 +80,7 @@ LL |         let f = internally_create;
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` method
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:122:13
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:140:13
    |
 LL |             S(marker::PhantomData).create_out_of_thin_air()
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |             S(marker::PhantomData).create_out_of_thin_air()
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:139:19
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:158:19
    |
 LL |             match send_message::<_ /* ?0 */>() {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
new file mode 100644
index 00000000000..4138e9f8c86
--- /dev/null
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr
@@ -0,0 +1,116 @@
+error: never type fallback affects this call to an `unsafe` function
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:13:18
+   |
+LL |         unsafe { mem::zeroed() }
+   |                  ^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+   = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default
+
+error: never type fallback affects this call to an `unsafe` function
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:30:13
+   |
+LL |             core::mem::transmute(Zst)
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+
+error: never type fallback affects this union access
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:47:18
+   |
+LL |         unsafe { Union { a: () }.b }
+   |                  ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+
+error: never type fallback affects this raw pointer dereference
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:58:18
+   |
+LL |         unsafe { *ptr::from_ref(&()).cast() }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+
+error: never type fallback affects this call to an `unsafe` function
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:18
+   |
+LL |         unsafe { internally_create(x) }
+   |                  ^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+
+error: never type fallback affects this call to an `unsafe` function
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:97:18
+   |
+LL |         unsafe { zeroed() }
+   |                  ^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+
+error: never type fallback affects this `unsafe` function
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:92:22
+   |
+LL |         let zeroed = mem::zeroed;
+   |                      ^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+
+error: never type fallback affects this `unsafe` function
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:115:17
+   |
+LL |         let f = internally_create;
+   |                 ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+
+error: never type fallback affects this call to an `unsafe` method
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:140:13
+   |
+LL |             S(marker::PhantomData).create_out_of_thin_air()
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+
+error: never type fallback affects this call to an `unsafe` function
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:158:19
+   |
+LL |             match send_message::<_ /* ?0 */>() {
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |         msg_send!();
+   |         ----------- in this macro invocation
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+   = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: the type `!` does not permit zero-initialization
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:13:18
+   |
+LL |         unsafe { mem::zeroed() }
+   |                  ^^^^^^^^^^^^^ this code causes undefined behavior when executed
+   |
+   = note: the `!` type has no valid value
+   = note: `#[warn(invalid_value)]` on by default
+
+error: aborting due to 10 previous errors; 1 warning emitted
+
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
index d65bfee843e..c96f4dda3f8 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
@@ -1,4 +1,9 @@
-//@ check-pass
+//@ revisions: e2015 e2024
+//@[e2015] check-pass
+//@[e2024] check-fail
+//@[e2024] edition:2024
+//@[e2024] compile-flags: -Zunstable-options
+
 use std::{marker, mem, ptr};
 
 fn main() {}
@@ -6,8 +11,10 @@ fn main() {}
 fn _zero() {
     if false {
         unsafe { mem::zeroed() }
-        //~^ warn: never type fallback affects this call to an `unsafe` function
+        //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
+        //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
         //~| warn: this will change its meaning in a future release!
+        //[e2024]~| warning: the type `!` does not permit zero-initialization
     } else {
         return;
     };
@@ -21,7 +28,8 @@ fn _trans() {
         unsafe {
             struct Zst;
             core::mem::transmute(Zst)
-            //~^ warn: never type fallback affects this call to an `unsafe` function
+            //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
+            //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
             //~| warn: this will change its meaning in a future release!
         }
     } else {
@@ -37,7 +45,8 @@ fn _union() {
         }
 
         unsafe { Union { a: () }.b }
-        //~^ warn: never type fallback affects this union access
+        //[e2015]~^ warn: never type fallback affects this union access
+        //[e2024]~^^ error: never type fallback affects this union access
         //~| warn: this will change its meaning in a future release!
     } else {
         return;
@@ -47,7 +56,8 @@ fn _union() {
 fn _deref() {
     if false {
         unsafe { *ptr::from_ref(&()).cast() }
-        //~^ warn: never type fallback affects this raw pointer dereference
+        //[e2015]~^ warn: never type fallback affects this raw pointer dereference
+        //[e2024]~^^ error: never type fallback affects this raw pointer dereference
         //~| warn: this will change its meaning in a future release!
     } else {
         return;
@@ -57,7 +67,9 @@ fn _deref() {
 fn _only_generics() {
     if false {
         unsafe fn internally_create<T>(_: Option<T>) {
-            let _ = mem::zeroed::<T>();
+            unsafe {
+                let _ = mem::zeroed::<T>();
+            }
         }
 
         // We need the option (and unwrap later) to call a function in a way,
@@ -65,7 +77,8 @@ fn _only_generics() {
         let x = None;
 
         unsafe { internally_create(x) }
-        //~^ warn: never type fallback affects this call to an `unsafe` function
+        //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
+        //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
         //~| warn: this will change its meaning in a future release!
 
         x.unwrap()
@@ -77,11 +90,13 @@ fn _only_generics() {
 fn _stored_function() {
     if false {
         let zeroed = mem::zeroed;
-        //~^ warn: never type fallback affects this `unsafe` function
+        //[e2015]~^ warn: never type fallback affects this `unsafe` function
+        //[e2024]~^^ error: never type fallback affects this `unsafe` function
         //~| warn: this will change its meaning in a future release!
 
         unsafe { zeroed() }
-        //~^ warn: never type fallback affects this call to an `unsafe` function
+        //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
+        //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
         //~| warn: this will change its meaning in a future release!
     } else {
         return;
@@ -91,12 +106,15 @@ fn _stored_function() {
 fn _only_generics_stored_function() {
     if false {
         unsafe fn internally_create<T>(_: Option<T>) {
-            let _ = mem::zeroed::<T>();
+            unsafe {
+                let _ = mem::zeroed::<T>();
+            }
         }
 
         let x = None;
         let f = internally_create;
-        //~^ warn: never type fallback affects this `unsafe` function
+        //[e2015]~^ warn: never type fallback affects this `unsafe` function
+        //[e2024]~^^ error: never type fallback affects this `unsafe` function
         //~| warn: this will change its meaning in a future release!
 
         unsafe { f(x) }
@@ -120,7 +138,8 @@ fn _method() {
     if false {
         unsafe {
             S(marker::PhantomData).create_out_of_thin_air()
-            //~^ warn: never type fallback affects this call to an `unsafe` method
+            //[e2015]~^ warn: never type fallback affects this call to an `unsafe` method
+            //[e2024]~^^ error: never type fallback affects this call to an `unsafe` method
             //~| warn: this will change its meaning in a future release!
         }
     } else {
@@ -137,7 +156,8 @@ fn _objc() {
     macro_rules! msg_send {
         () => {
             match send_message::<_ /* ?0 */>() {
-                //~^ warn: never type fallback affects this call to an `unsafe` function
+                //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function
+                //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function
                 //~| warn: this will change its meaning in a future release!
                 Ok(x) => x,
                 Err(_) => loop {},
diff --git a/tests/ui/nll/closure-captures.stderr b/tests/ui/nll/closure-captures.stderr
index 5233f0b2462..828974c517e 100644
--- a/tests/ui/nll/closure-captures.stderr
+++ b/tests/ui/nll/closure-captures.stderr
@@ -1,38 +1,46 @@
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/closure-captures.rs:7:5
    |
-LL | fn one_closure(x: i32) {
-   |                - help: consider changing this to be mutable: `mut x`
-LL |     ||
 LL |     x = 1;
    |     ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn one_closure(mut x: i32) {
+   |                +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/closure-captures.rs:9:5
    |
-LL | fn one_closure(x: i32) {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |     x = 1;
    |     ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn one_closure(mut x: i32) {
+   |                +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/closure-captures.rs:15:9
    |
-LL | fn two_closures(x: i32) {
-   |                 - help: consider changing this to be mutable: `mut x`
-...
 LL |         x = 1;
    |         ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn two_closures(mut x: i32) {
+   |                 +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/closure-captures.rs:19:9
    |
-LL | fn two_closures(x: i32) {
-   |                 - help: consider changing this to be mutable: `mut x`
-...
 LL |         x = 1;
    |         ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn two_closures(mut x: i32) {
+   |                 +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:27:9
@@ -67,11 +75,13 @@ LL |     x = 1;});
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/closure-captures.rs:39:10
    |
-LL | fn two_closures_ref(x: i32) {
-   |                     - help: consider changing this to be mutable: `mut x`
-...
 LL |          x = 1;}
    |          ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn two_closures_ref(mut x: i32) {
+   |                     +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:38:9
@@ -91,11 +101,13 @@ LL |          x = 1;}
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/closure-captures.rs:43:5
    |
-LL | fn two_closures_ref(x: i32) {
-   |                     - help: consider changing this to be mutable: `mut x`
-...
 LL |     x = 1;});
    |     ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn two_closures_ref(mut x: i32) {
+   |                     +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:42:9
diff --git a/tests/ui/nll/coroutine-upvar-mutability.stderr b/tests/ui/nll/coroutine-upvar-mutability.stderr
index 8b9be877c8f..02c01130176 100644
--- a/tests/ui/nll/coroutine-upvar-mutability.stderr
+++ b/tests/ui/nll/coroutine-upvar-mutability.stderr
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/coroutine-upvar-mutability.rs:10:9
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |         x = 1;
    |         ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/nll/issue-46023.stderr b/tests/ui/nll/issue-46023.stderr
index 062e07407ce..d071c29271c 100644
--- a/tests/ui/nll/issue-46023.stderr
+++ b/tests/ui/nll/issue-46023.stderr
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/issue-46023.rs:5:9
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |         x = 1;
    |         ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr
index 812f7a0692f..4fea52fec6e 100644
--- a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr
+++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr
@@ -5,7 +5,7 @@ LL | fn panic(info: PanicInfo) -> () {}
    |                ^^^^^^^^^ expected `&PanicInfo<'_>`, found `PanicInfo<'_>`
    |
    = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !`
-              found signature `for<'a> fn(PanicInfo<'a>)`
+              found signature `for<'a> fn(PanicInfo<'a>) -> ()`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/bad-let-else-statement.rs b/tests/ui/parser/bad-let-else-statement.rs
index ff6619cbc98..3ede26dbcd0 100644
--- a/tests/ui/parser/bad-let-else-statement.rs
+++ b/tests/ui/parser/bad-let-else-statement.rs
@@ -147,14 +147,14 @@ fn o() -> Result<(), ()> {
     };
 }
 
-fn p() {
-    let 0 = become {
-        ()
-    } else {
-        //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
-        return;
-    };
-}
+// fn p() { // FIXME(explicit_tail_calls): this currently trips an assertion...
+//     let 0 = become {
+//         ()
+//     } else {
+//         // ~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
+//         return;
+//     };
+// }
 
 fn q() {
     let foo = |x: i32| {
diff --git a/tests/ui/parser/bad-let-else-statement.stderr b/tests/ui/parser/bad-let-else-statement.stderr
index 0bf6a346dfb..79d722bb7ac 100644
--- a/tests/ui/parser/bad-let-else-statement.stderr
+++ b/tests/ui/parser/bad-let-else-statement.stderr
@@ -204,19 +204,6 @@ LL ~     }) else {
    |
 
 error: right curly brace `}` before `else` in a `let...else` statement not allowed
-  --> $DIR/bad-let-else-statement.rs:153:5
-   |
-LL |     } else {
-   |     ^
-   |
-help: wrap the expression in parentheses
-   |
-LL ~     let 0 = become ({
-LL |         ()
-LL ~     }) else {
-   |
-
-error: right curly brace `}` before `else` in a `let...else` statement not allowed
   --> $DIR/bad-let-else-statement.rs:163:5
    |
 LL |     } else {
@@ -325,5 +312,5 @@ LL | |     } else {
    = note: this pattern will always match, so the `else` clause is useless
    = help: consider removing the `else` clause
 
-error: aborting due to 20 previous errors; 5 warnings emitted
+error: aborting due to 19 previous errors; 5 warnings emitted
 
diff --git a/tests/ui/parser/issues/issue-105366.fixed b/tests/ui/parser/issues/issue-105366.fixed
index 7157b647524..95419dc07f2 100644
--- a/tests/ui/parser/issues/issue-105366.fixed
+++ b/tests/ui/parser/issues/issue-105366.fixed
@@ -1,5 +1,6 @@
 //@ run-rustfix
 
+#[allow(dead_code)]
 struct Foo;
 
 impl From<i32> for Foo {
diff --git a/tests/ui/parser/issues/issue-105366.rs b/tests/ui/parser/issues/issue-105366.rs
index dc3cb8b343d..3278b737991 100644
--- a/tests/ui/parser/issues/issue-105366.rs
+++ b/tests/ui/parser/issues/issue-105366.rs
@@ -1,5 +1,6 @@
 //@ run-rustfix
 
+#[allow(dead_code)]
 struct Foo;
 
 fn From<i32> for Foo {
diff --git a/tests/ui/parser/issues/issue-105366.stderr b/tests/ui/parser/issues/issue-105366.stderr
index 18c04dfaf20..195305a2ec8 100644
--- a/tests/ui/parser/issues/issue-105366.stderr
+++ b/tests/ui/parser/issues/issue-105366.stderr
@@ -1,5 +1,5 @@
 error: you might have meant to write `impl` instead of `fn`
-  --> $DIR/issue-105366.rs:5:1
+  --> $DIR/issue-105366.rs:6:1
    |
 LL | fn From<i32> for Foo {
    | ^^
diff --git a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr
index 41d1b79d97d..ed71a39ff7e 100644
--- a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr
+++ b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr
@@ -78,11 +78,11 @@ LL |         | Err(a @ b @ a)
 help: consider making this binding mutable
    |
 LL |         Ok(a @ b @ mut a)
-   |                    ~~~~~
+   |                    +++
 help: to modify the original value, take a borrow instead
    |
 LL |         Ok(a @ b @ ref mut a)
-   |                    ~~~~~~~~~
+   |                    +++++++
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
index 1e7b990b67c..a1049701dc3 100644
--- a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
+++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -22,11 +22,11 @@ LL |     _x1 = U;
 help: consider making this binding mutable
    |
 LL |     let [ref _x0_hold, mut _x1, ref xs_hold @ ..] = arr;
-   |                        ~~~~~~~
+   |                        +++
 help: to modify the original value, take a borrow instead
    |
 LL |     let [ref _x0_hold, ref mut _x1, ref xs_hold @ ..] = arr;
-   |                        ~~~~~~~~~~~
+   |                        +++++++
 
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
   --> $DIR/borrowck-move-ref-pattern.rs:11:10
@@ -86,11 +86,11 @@ LL |     _x1 = U;
 help: consider making this binding mutable
    |
 LL |     let (ref _x0, mut _x1, ref _x2, ..) = tup;
-   |                   ~~~~~~~
+   |                   +++
 help: to modify the original value, take a borrow instead
    |
 LL |     let (ref _x0, ref mut _x1, ref _x2, ..) = tup;
-   |                   ~~~~~~~~~~~
+   |                   +++++++
 
 error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-move-ref-pattern.rs:24:20
diff --git a/tests/ui/pattern/mut-ref-mut-2021.stderr b/tests/ui/pattern/mut-ref-mut-2021.stderr
index ebf7979edb6..228afed2026 100644
--- a/tests/ui/pattern/mut-ref-mut-2021.stderr
+++ b/tests/ui/pattern/mut-ref-mut-2021.stderr
@@ -9,11 +9,11 @@ LL |     a = 42;
 help: consider making this binding mutable
    |
 LL |     let Foo(mut a) = Foo(0);
-   |             ~~~~~
+   |             +++
 help: to modify the original value, take a borrow instead
    |
 LL |     let Foo(ref mut a) = Foo(0);
-   |             ~~~~~~~~~
+   |             +++++++
 
 error[E0384]: cannot assign twice to immutable variable `a`
   --> $DIR/mut-ref-mut-2021.rs:15:5
diff --git a/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr b/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr
index 68538255edd..e9c2fccaba2 100644
--- a/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr
+++ b/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
   --> $DIR/patkind-ref-binding-issue-114896.rs:7:9
    |
-LL |         let &b = a;
-   |             -- help: consider changing this to be mutable: `&(mut b)`
 LL |         b.make_ascii_uppercase();
    |         ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |         let &(mut b) = a;
+   |             ~~~~~  +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr b/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr
index 39283133ac7..e93b8bbaccc 100644
--- a/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr
+++ b/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/patkind-ref-binding-issue-122415.rs:7:12
    |
-LL | fn foo(&x: &i32) {
-   |        -- help: consider changing this to be mutable: `&(mut x)`
 LL |     mutate(&mut x);
    |            ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn foo(&(mut x): &i32) {
+   |        ~~~~~  +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr
index 1694d514f42..f15a0ae6138 100644
--- a/tests/ui/range/issue-54505-no-std.stderr
+++ b/tests/ui/range/issue-54505-no-std.stderr
@@ -7,7 +7,7 @@ LL |     take_range(0..1);
    |     arguments to this function are incorrect
    |
    = note: expected reference `&_`
-                 found struct `Range<{integer}>`
+                 found struct `core::ops::Range<{integer}>`
 note: function defined here
   --> $DIR/issue-54505-no-std.rs:25:4
    |
@@ -27,7 +27,7 @@ LL |     take_range(1..);
    |     arguments to this function are incorrect
    |
    = note: expected reference `&_`
-                 found struct `RangeFrom<{integer}>`
+                 found struct `core::ops::RangeFrom<{integer}>`
 note: function defined here
   --> $DIR/issue-54505-no-std.rs:25:4
    |
@@ -67,7 +67,7 @@ LL |     take_range(0..=1);
    |     arguments to this function are incorrect
    |
    = note: expected reference `&_`
-                 found struct `RangeInclusive<{integer}>`
+                 found struct `core::ops::RangeInclusive<{integer}>`
 note: function defined here
   --> $DIR/issue-54505-no-std.rs:25:4
    |
diff --git a/tests/ui/recursion/issue-83150.rs b/tests/ui/recursion/issue-83150.rs
index b74b2adfeab..b3ddf88c449 100644
--- a/tests/ui/recursion/issue-83150.rs
+++ b/tests/ui/recursion/issue-83150.rs
@@ -1,7 +1,6 @@
 //@ build-fail
 //@ compile-flags: -Copt-level=0
 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
-//~^^^ ERROR overflow evaluating the requirement
 //@ ignore-compare-mode-next-solver (hangs)
 
 fn main() {
@@ -9,6 +8,8 @@ fn main() {
     func(&mut iter)
 }
 
-fn func<T: Iterator<Item = u8>>(iter: &mut T) { //~ WARN function cannot return without recursing
+fn func<T: Iterator<Item = u8>>(iter: &mut T) {
+    //~^ WARN function cannot return without recursing
     func(&mut iter.map(|x| x + 1))
+    //~^ ERROR reached the type-length limit
 }
diff --git a/tests/ui/recursion/issue-83150.stderr b/tests/ui/recursion/issue-83150.stderr
index 783f9cf7632..127de98ddc5 100644
--- a/tests/ui/recursion/issue-83150.stderr
+++ b/tests/ui/recursion/issue-83150.stderr
@@ -1,21 +1,23 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-83150.rs:12:1
+  --> $DIR/issue-83150.rs:11:1
    |
 LL | fn func<T: Iterator<Item = u8>>(iter: &mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
 LL |     func(&mut iter.map(|x| x + 1))
    |     ------------------------------ recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>: Iterator`
+error: reached the type-length limit while instantiating `<&mut Map<&mut Map<&mut ..., ...>, ...> as Iterator>::map::<..., ...>`
+  --> $DIR/issue-83150.rs:13:15
    |
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
-   = note: required for `&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator`
-   = note: 65 redundant requirements hidden
-   = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator`
+LL |     func(&mut iter.map(|x| x + 1))
+   |               ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a `#![type_length_limit="23068663"]` attribute to your crate
+   = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type.txt'
 
 error: aborting due to 1 previous error; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr
new file mode 100644
index 00000000000..e2e57fe0e73
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr
@@ -0,0 +1,288 @@
+error: layout_of(Univariant) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:38:1
+   |
+LL | enum Univariant {
+   | ^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariants) = Layout {
+           size: Size(8 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+                   Layout {
+                       size: Size(8 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:45:1
+   |
+LL | enum TwoVariants {
+   | ^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherField) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:57:1
+   |
+LL | enum DeadBranchHasOtherField {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr
new file mode 100644
index 00000000000..6ecdab1cc14
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr
@@ -0,0 +1,288 @@
+error: layout_of(Univariant) = Layout {
+           size: Size(1 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(1 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:38:1
+   |
+LL | enum Univariant {
+   | ^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariants) = Layout {
+           size: Size(2 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(1 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:45:1
+   |
+LL | enum TwoVariants {
+   | ^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherField) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:57:1
+   |
+LL | enum DeadBranchHasOtherField {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr
new file mode 100644
index 00000000000..e2e57fe0e73
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr
@@ -0,0 +1,288 @@
+error: layout_of(Univariant) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:38:1
+   |
+LL | enum Univariant {
+   | ^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariants) = Layout {
+           size: Size(8 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+                   Layout {
+                       size: Size(8 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:45:1
+   |
+LL | enum TwoVariants {
+   | ^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherField) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:57:1
+   |
+LL | enum DeadBranchHasOtherField {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/repr/repr-c-dead-variants.rs b/tests/ui/repr/repr-c-dead-variants.rs
new file mode 100644
index 00000000000..f113588e83f
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.rs
@@ -0,0 +1,63 @@
+#![feature(no_core, rustc_attrs, lang_items)]
+#![allow(dead_code)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+// See also: repr-c-int-dead-variants.rs
+
+//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+
+// This test depends on the value of the `c_enum_min_bits` target option.
+// As there's no way to actually check it from UI test, we only run this test on a subset of archs.
+// Four archs specifically are chosen: one for major architectures (x86_64, i686, aarch64)
+// and `armebv7r-none-eabi` that has `c_enum_min_bits` set to 8.
+
+//@ revisions: aarch64-unknown-linux-gnu
+//@[aarch64-unknown-linux-gnu] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64-unknown-linux-gnu] needs-llvm-components: aarch64
+
+//@ revisions: i686-pc-windows-msvc
+//@[i686-pc-windows-msvc] compile-flags: --target i686-pc-windows-gnu
+//@[i686-pc-windows-msvc] needs-llvm-components: x86
+
+//@ revisions: x86_64-unknown-linux-gnu
+//@[x86_64-unknown-linux-gnu] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64-unknown-linux-gnu] needs-llvm-components: x86
+//
+//@ revisions: armebv7r-none-eabi
+//@[armebv7r-none-eabi] compile-flags: --target armebv7r-none-eabi
+//@[armebv7r-none-eabi] needs-llvm-components: arm
+
+// A simple uninhabited type.
+enum Void {}
+
+// Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
+#[repr(C)]
+#[rustc_layout(debug)]
+enum Univariant { //~ ERROR layout_of
+    Variant(Void),
+}
+
+// ADTs with variants that have fields must have space allocated for those fields.
+#[repr(C)]
+#[rustc_layout(debug)]
+enum TwoVariants { //~ ERROR layout_of
+    Variant1(Void),
+    Variant2(u8),
+}
+
+// Some targets have 4-byte-aligned u64, make it always 8-byte-aligned.
+#[repr(C, align(8))]
+struct Align8U64(u64);
+
+// This one is 2 x u64: we reserve space for fields in a dead branch.
+#[repr(C)]
+#[rustc_layout(debug)]
+enum DeadBranchHasOtherField { //~ ERROR layout_of
+    Variant1(Void, Align8U64),
+    Variant2(u8),
+}
+
+#[lang = "sized"]
+trait Sized {}
diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr
new file mode 100644
index 00000000000..e2e57fe0e73
--- /dev/null
+++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr
@@ -0,0 +1,288 @@
+error: layout_of(Univariant) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:38:1
+   |
+LL | enum Univariant {
+   | ^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariants) = Layout {
+           size: Size(8 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+                   Layout {
+                       size: Size(8 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(4 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:45:1
+   |
+LL | enum TwoVariants {
+   | ^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherField) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-dead-variants.rs:57:1
+   |
+LL | enum DeadBranchHasOtherField {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/repr/repr-c-int-dead-variants.rs b/tests/ui/repr/repr-c-int-dead-variants.rs
new file mode 100644
index 00000000000..8d2b39bd648
--- /dev/null
+++ b/tests/ui/repr/repr-c-int-dead-variants.rs
@@ -0,0 +1,38 @@
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+// See also: repr-c-dead-variants.rs
+
+//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+
+// A simple uninhabited type.
+enum Void {}
+
+// Compiler must not remove dead variants of `#[repr(C, int)]` ADTs.
+#[repr(C, u8)]
+#[rustc_layout(debug)]
+enum UnivariantU8 { //~ ERROR layout_of
+    Variant(Void),
+}
+
+// ADTs with variants that have fields must have space allocated for those fields.
+#[repr(C, u8)]
+#[rustc_layout(debug)]
+enum TwoVariantsU8 { //~ ERROR layout_of
+    Variant1(Void),
+    Variant2(u8),
+}
+
+// Some targets have 4-byte-aligned u64, make it always 8-byte-aligned.
+#[repr(C, align(8))]
+struct Align8U64(u64);
+
+// This one is 2 x u64: we reserve space for fields in a dead branch.
+#[repr(C, u8)]
+#[rustc_layout(debug)]
+enum DeadBranchHasOtherFieldU8 { //~ ERROR layout_of
+    Variant1(Void, Align8U64),
+    Variant2(u8),
+}
+
+fn main() {}
diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr
new file mode 100644
index 00000000000..f7df576df24
--- /dev/null
+++ b/tests/ui/repr/repr-c-int-dead-variants.stderr
@@ -0,0 +1,288 @@
+error: layout_of(UnivariantU8) = Layout {
+           size: Size(1 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Uninhabited,
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=0,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(1 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
+       }
+  --> $DIR/repr-c-int-dead-variants.rs:14:1
+   |
+LL | enum UnivariantU8 {
+   | ^^^^^^^^^^^^^^^^^
+
+error: layout_of(TwoVariantsU8) = Layout {
+           size: Size(2 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: ScalarPair(
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(1 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+                   Layout {
+                       size: Size(2 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(1 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
+       }
+  --> $DIR/repr-c-int-dead-variants.rs:21:1
+   |
+LL | enum TwoVariantsU8 {
+   | ^^^^^^^^^^^^^^^^^^
+
+error: layout_of(DeadBranchHasOtherFieldU8) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Uninhabited,
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                               1,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: Some(
+                           Align(8 bytes),
+                       ),
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+                   Layout {
+                       size: Size(16 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(8 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(8 bytes),
+                   },
+               ],
+           },
+           max_repr_align: Some(
+               Align(8 bytes),
+           ),
+           unadjusted_abi_align: Align(8 bytes),
+       }
+  --> $DIR/repr-c-int-dead-variants.rs:33:1
+   |
+LL | enum DeadBranchHasOtherFieldU8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr
index 3c44c1c249c..2f624f24804 100644
--- a/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr
+++ b/tests/ui/resolve/field-and-method-in-self-not-available-in-assoc-fn.stderr
@@ -2,7 +2,7 @@ error[E0425]: cannot find value `field` in this scope
   --> $DIR/field-and-method-in-self-not-available-in-assoc-fn.rs:11:9
    |
 LL |     field: u32,
-   |     ---------- a field by that name exists in `Self`
+   |     ----- a field by that name exists in `Self`
 ...
 LL |     fn field(&self) -> u32 {
    |        ----- a method by that name is available on `Self` here
@@ -14,7 +14,7 @@ error[E0425]: cannot find value `field` in this scope
   --> $DIR/field-and-method-in-self-not-available-in-assoc-fn.rs:12:15
    |
 LL |     field: u32,
-   |     ---------- a field by that name exists in `Self`
+   |     ----- a field by that name exists in `Self`
 ...
 LL |     fn field(&self) -> u32 {
    |        ----- a method by that name is available on `Self` here
diff --git a/tests/ui/resolve/issue-2356.stderr b/tests/ui/resolve/issue-2356.stderr
index 5f75ae98870..74a2c9268a2 100644
--- a/tests/ui/resolve/issue-2356.stderr
+++ b/tests/ui/resolve/issue-2356.stderr
@@ -2,7 +2,7 @@ error[E0425]: cannot find value `whiskers` in this scope
   --> $DIR/issue-2356.rs:39:5
    |
 LL |   whiskers: isize,
-   |   --------------- a field by that name exists in `Self`
+   |   -------- a field by that name exists in `Self`
 ...
 LL |     whiskers -= other;
    |     ^^^^^^^^
@@ -35,7 +35,7 @@ error[E0425]: cannot find value `whiskers` in this scope
   --> $DIR/issue-2356.rs:84:5
    |
 LL |   whiskers: isize,
-   |   --------------- a field by that name exists in `Self`
+   |   -------- a field by that name exists in `Self`
 ...
 LL |     whiskers = 4;
    |     ^^^^^^^^
diff --git a/tests/ui/resolve/issue-60057.stderr b/tests/ui/resolve/issue-60057.stderr
index a2ab8644353..8737cf77001 100644
--- a/tests/ui/resolve/issue-60057.stderr
+++ b/tests/ui/resolve/issue-60057.stderr
@@ -2,7 +2,7 @@ error[E0425]: cannot find value `banana` in this scope
   --> $DIR/issue-60057.rs:8:21
    |
 LL |     banana: u8,
-   |     ---------- a field by that name exists in `Self`
+   |     ------ a field by that name exists in `Self`
 ...
 LL |             banana: banana
    |                     ^^^^^^
diff --git a/tests/ui/resolve/resolve-primitive-fallback.stderr b/tests/ui/resolve/resolve-primitive-fallback.stderr
index e3a5d4edcf1..d0583966459 100644
--- a/tests/ui/resolve/resolve-primitive-fallback.stderr
+++ b/tests/ui/resolve/resolve-primitive-fallback.stderr
@@ -24,13 +24,15 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/resolve-primitive-fallback.rs:3:5
    |
 LL |     std::mem::size_of(u16);
-   |     ^^^^^^^^^^^^^^^^^ ---
-   |                       |
-   |                       unexpected argument
-   |                       help: remove the extra argument
+   |     ^^^^^^^^^^^^^^^^^ --- unexpected argument
    |
 note: function defined here
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+help: remove the extra argument
+   |
+LL -     std::mem::size_of(u16);
+LL +     std::mem::size_of();
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr
index 0306c8af87d..5662021a2d5 100644
--- a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr
+++ b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr
@@ -2,7 +2,7 @@ error[E0425]: cannot find value `config` in this scope
   --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:7:16
    |
 LL |     config: String,
-   |     -------------- a field by that name exists in `Self`
+   |     ------ a field by that name exists in `Self`
 ...
 LL |         Self { config }
    |                ^^^^^^ help: a local variable with a similar name exists: `cofig`
@@ -11,7 +11,7 @@ error[E0425]: cannot find value `config` in this scope
   --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:11:20
    |
 LL |     config: String,
-   |     -------------- a field by that name exists in `Self`
+   |     ------ a field by that name exists in `Self`
 ...
 LL |         println!("{config}");
    |                    ^^^^^^ help: a local variable with a similar name exists: `cofig`
diff --git a/tests/ui/resolve/unresolved_static_type_field.stderr b/tests/ui/resolve/unresolved_static_type_field.stderr
index e3de0a3fb74..f039eef2e06 100644
--- a/tests/ui/resolve/unresolved_static_type_field.stderr
+++ b/tests/ui/resolve/unresolved_static_type_field.stderr
@@ -2,7 +2,7 @@ error[E0425]: cannot find value `cx` in this scope
   --> $DIR/unresolved_static_type_field.rs:9:11
    |
 LL |     cx: bool,
-   |     -------- a field by that name exists in `Self`
+   |     -- a field by that name exists in `Self`
 ...
 LL |         f(cx);
    |           ^^
diff --git a/tests/ui/return/tail-expr-as-potential-return.rs b/tests/ui/return/tail-expr-as-potential-return.rs
index 37dee1c19db..11ecddb049b 100644
--- a/tests/ui/return/tail-expr-as-potential-return.rs
+++ b/tests/ui/return/tail-expr-as-potential-return.rs
@@ -1,3 +1,5 @@
+//@ edition:2018
+
 // > Suggest returning tail expressions that match return type
 // >
 // > Some newcomers are confused by the behavior of tail expressions,
@@ -8,24 +10,24 @@
 //
 // This test was amended to also serve as a regression test for #92308, where
 // this suggestion would not trigger with async functions.
-//
-//@ edition:2018
 
 fn main() {
 }
 
 fn foo(x: bool) -> Result<f64, i32> {
     if x {
-        Err(42) //~ ERROR mismatched types
-                //| HELP you might have meant to return this value
+        Err(42)
+        //~^ ERROR mismatched types
+        //~| HELP you might have meant to return this value
     }
     Ok(42.0)
 }
 
 async fn bar(x: bool) -> Result<f64, i32> {
     if x {
-        Err(42) //~ ERROR mismatched types
-                //| HELP you might have meant to return this value
+        Err(42)
+        //~^ ERROR mismatched types
+        //~| HELP you might have meant to return this value
     }
     Ok(42.0)
 }
@@ -40,8 +42,26 @@ impl<T> Identity for T {
 
 async fn foo2() -> i32 {
     if true {
-        1i32 //~ ERROR mismatched types
-            //| HELP you might have meant to return this value
+        1i32
+        //~^ ERROR mismatched types
+        //~| HELP you might have meant to return this value
     }
     0
 }
+
+struct Receiver;
+impl Receiver {
+    fn generic<T>(self) -> Option<T> {
+        None
+    }
+}
+fn method() -> Option<i32> {
+    if true {
+        Receiver.generic();
+        //~^ ERROR type annotations needed
+        //~| HELP consider specifying the generic argument
+        //~| HELP you might have meant to return this to infer its type parameters
+    }
+
+    None
+}
diff --git a/tests/ui/return/tail-expr-as-potential-return.stderr b/tests/ui/return/tail-expr-as-potential-return.stderr
index ccb208fc6c4..635a9e06633 100644
--- a/tests/ui/return/tail-expr-as-potential-return.stderr
+++ b/tests/ui/return/tail-expr-as-potential-return.stderr
@@ -1,10 +1,11 @@
 error[E0308]: mismatched types
-  --> $DIR/tail-expr-as-potential-return.rs:27:9
+  --> $DIR/tail-expr-as-potential-return.rs:28:9
    |
 LL | /     if x {
 LL | |         Err(42)
    | |         ^^^^^^^ expected `()`, found `Result<_, {integer}>`
-LL | |                 //| HELP you might have meant to return this value
+LL | |
+LL | |
 LL | |     }
    | |_____- expected this to be `()`
    |
@@ -16,12 +17,13 @@ LL |         return Err(42);
    |         ++++++        +
 
 error[E0308]: mismatched types
-  --> $DIR/tail-expr-as-potential-return.rs:43:9
+  --> $DIR/tail-expr-as-potential-return.rs:45:9
    |
 LL | /     if true {
 LL | |         1i32
    | |         ^^^^ expected `()`, found `i32`
-LL | |             //| HELP you might have meant to return this value
+LL | |
+LL | |
 LL | |     }
    | |_____- expected this to be `()`
    |
@@ -36,7 +38,8 @@ error[E0308]: mismatched types
 LL | /     if x {
 LL | |         Err(42)
    | |         ^^^^^^^ expected `()`, found `Result<_, {integer}>`
-LL | |                 //| HELP you might have meant to return this value
+LL | |
+LL | |
 LL | |     }
    | |_____- expected this to be `()`
    |
@@ -47,6 +50,22 @@ help: you might have meant to return this value
 LL |         return Err(42);
    |         ++++++        +
 
-error: aborting due to 3 previous errors
+error[E0282]: type annotations needed
+  --> $DIR/tail-expr-as-potential-return.rs:60:18
+   |
+LL |         Receiver.generic();
+   |                  ^^^^^^^ cannot infer type of the type parameter `T` declared on the method `generic`
+   |
+help: consider specifying the generic argument
+   |
+LL |         Receiver.generic::<T>();
+   |                         +++++
+help: you might have meant to return this to infer its type parameters
+   |
+LL |         return Receiver.generic();
+   |         ++++++
+
+error: aborting due to 4 previous errors
 
-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/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
index af88a73b4d6..63c353c7d66 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
@@ -1,12 +1,16 @@
 //@ known-bug: #110395
+//@ failure-status: 101
+//@ normalize-stderr-test ".*note: .*\n\n" -> ""
+//@ normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
+//@ rustc-env:RUST_BACKTRACE=0
 // FIXME(effects) check-pass
-// FIXME(effects) fix intrinsics const parameter counting
+//@ compile-flags: -Znext-solver
 
 #![crate_type = "lib"]
 #![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs, staged_api)]
-#![feature(fundamental)]
+#![feature(fundamental, marker_trait_attr)]
 #![feature(const_trait_impl, effects, const_mut_refs)]
-#![allow(internal_features)]
+#![allow(internal_features, incomplete_features)]
 #![no_std]
 #![no_core]
 #![stable(feature = "minicore", since = "1.0.0")]
@@ -532,3 +536,35 @@ fn test_const_eval_select() {
 
     const_eval_select((), const_fn, rt_fn);
 }
+
+mod effects {
+    use super::Sized;
+
+    #[lang = "EffectsNoRuntime"]
+    pub struct NoRuntime;
+    #[lang = "EffectsMaybe"]
+    pub struct Maybe;
+    #[lang = "EffectsRuntime"]
+    pub struct Runtime;
+
+    #[lang = "EffectsCompat"]
+    pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {}
+
+    impl Compat<false> for NoRuntime {}
+    impl Compat<true> for Runtime {}
+    impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {}
+
+    #[lang = "EffectsTyCompat"]
+    #[marker]
+    pub trait TyCompat<T: ?Sized> {}
+
+    impl<T: ?Sized> TyCompat<T> for T {}
+    impl<T: ?Sized> TyCompat<T> for Maybe {}
+    impl<T: ?Sized> TyCompat<Maybe> for T {}
+
+    #[lang = "EffectsIntersection"]
+    pub trait Intersection {
+        #[lang = "EffectsIntersectionOutput"]
+        type Output: ?Sized;
+    }
+}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr
index 1963332b856..823ab69df9c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr
@@ -1,17 +1,13 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/minicore.rs:8:30
-   |
-LL | #![feature(const_trait_impl, effects, const_mut_refs)]
-   |                              ^^^^^^^
-   |
-   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
-   = note: `#[warn(incomplete_features)]` on by default
+error: the compiler unexpectedly panicked. this is a bug.
 
-error: requires `EffectsCompat` lang_item
-  --> $DIR/minicore.rs:455:9
-   |
-LL | impl<T: Clone> Clone for RefCell<T> {
-   |         ^^^^^
+query stack during panic:
+#0 [check_well_formed] checking that `<impl at $DIR/minicore.rs:459:1: 459:36>` is well-formed
+#1 [check_mod_type_wf] checking that types are well-formed in top-level module
+end of query stack
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: the compiler unexpectedly panicked. this is a bug.
 
+query stack during panic:
+#0 [check_well_formed] checking that `drop` is well-formed
+#1 [check_mod_type_wf] checking that types are well-formed in top-level module
+end of query stack
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr
deleted file mode 100644
index 4a949e90d85..00000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Index>::Output`
-  --> $DIR/issue-100222.rs:34:12
-   |
-LL |     fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
-   |            ^^^^^^^^^ types differ
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr
deleted file mode 100644
index 1bfce48d26a..00000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Index>::Output`
-  --> $DIR/issue-100222.rs:25:12
-   |
-LL |     fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
-   |            ^^^^^^^^^ types differ
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs
index 7949772a2b4..47f9fc664ce 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs
@@ -1,6 +1,7 @@
 //@ revisions: nn ny yn yy
-//@ known-bug: #110395
 //@ compile-flags: -Znext-solver
+//@ check-pass
+
 #![allow(incomplete_features)]
 #![feature(const_trait_impl, effects, associated_type_defaults, const_mut_refs)]
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr
deleted file mode 100644
index 4a949e90d85..00000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Index>::Output`
-  --> $DIR/issue-100222.rs:34:12
-   |
-LL |     fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
-   |            ^^^^^^^^^ types differ
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr
deleted file mode 100644
index 1bfce48d26a..00000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Index>::Output`
-  --> $DIR/issue-100222.rs:25:12
-   |
-LL |     fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
-   |            ^^^^^^^^^ types differ
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr
new file mode 100644
index 00000000000..80e7a45f57e
--- /dev/null
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!` or `::`, found keyword `impl`
+  --> $DIR/safe-impl-trait.rs:5:6
+   |
+LL | safe impl Bar for () { }
+   |      ^^^^ expected one of `!` or `::`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs
new file mode 100644
index 00000000000..57c03e4d896
--- /dev/null
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs
@@ -0,0 +1,8 @@
+//@ revisions: gated ungated
+#![cfg_attr(gated, feature(unsafe_extern_blocks))]
+
+trait Bar {}
+safe impl Bar for () { }
+//~^ ERROR expected one of `!` or `::`, found keyword `impl`
+
+fn main() {}
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr
new file mode 100644
index 00000000000..80e7a45f57e
--- /dev/null
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!` or `::`, found keyword `impl`
+  --> $DIR/safe-impl-trait.rs:5:6
+   |
+LL | safe impl Bar for () { }
+   |      ^^^^ expected one of `!` or `::`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr
new file mode 100644
index 00000000000..de84037f28c
--- /dev/null
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!` or `::`, found keyword `trait`
+  --> $DIR/safe-trait.rs:4:6
+   |
+LL | safe trait Foo {}
+   |      ^^^^^ expected one of `!` or `::`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs
new file mode 100644
index 00000000000..e73cb45b188
--- /dev/null
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs
@@ -0,0 +1,7 @@
+//@ revisions: gated ungated
+#![cfg_attr(gated, feature(unsafe_extern_blocks))]
+
+safe trait Foo {}
+//~^ ERROR expected one of `!` or `::`, found keyword `trait`
+
+fn main() {}
diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr
new file mode 100644
index 00000000000..de84037f28c
--- /dev/null
+++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!` or `::`, found keyword `trait`
+  --> $DIR/safe-trait.rs:4:6
+   |
+LL | safe trait Foo {}
+   |      ^^^^^ expected one of `!` or `::`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs
new file mode 100644
index 00000000000..8bf9f97e0b9
--- /dev/null
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs
@@ -0,0 +1,29 @@
+//! The same as the non-ICE test, but const eval will run typeck of
+//! `get` before running wfcheck (as that may in itself trigger const
+//! eval again, and thus cause bogus cycles). This used to ICE because
+//! we asserted that an error had already been emitted.
+
+use std::ops::Deref;
+
+struct Foo(u32);
+impl Foo {
+    const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
+        //~^ ERROR: `R` cannot be used as the type of `self`
+        //~| ERROR destructor of `R` cannot be evaluated at compile-time
+        self.0
+        //~^ ERROR cannot borrow here, since the borrowed element may contain interior mutability
+        //~| ERROR cannot call non-const fn `<R as Deref>::deref` in constant function
+    }
+}
+
+const FOO: () = {
+    let foo = Foo(1);
+    foo.get::<&Foo>();
+};
+
+const BAR: [(); {
+    FOO;
+    0
+}] = [];
+
+fn main() {}
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
new file mode 100644
index 00000000000..9e3851f9a6e
--- /dev/null
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
@@ -0,0 +1,46 @@
+error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
+  --> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9
+   |
+LL |         self.0
+   |         ^^^^
+   |
+   = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
+   = help: add `#![feature(const_refs_to_cell)]` 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[E0015]: cannot call non-const fn `<R as Deref>::deref` in constant functions
+  --> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9
+   |
+LL |         self.0
+   |         ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   |
+LL + #![feature(const_trait_impl)]
+   |
+
+error[E0493]: destructor of `R` cannot be evaluated at compile-time
+  --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43
+   |
+LL |     const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
+   |                                           ^^^^ the destructor for this type cannot be evaluated in constant functions
+...
+LL |     }
+   |     - value is dropped here
+
+error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+  --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49
+   |
+LL |     const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
+   |                                                 ^
+   |
+   = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
+   = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0015, E0493, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr
index 6fff086a89c..4cc69666b88 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr
@@ -9,7 +9,6 @@ LL |     fn get<R: Deref<Target = Self>>(self: R) -> u32 {
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
- ERROR rustc_hir_typeck::method::confirm Foo was a subtype of &Foo but now is not?
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/simd/simd-bitmask-notpow2.rs b/tests/ui/simd/simd-bitmask-notpow2.rs
new file mode 100644
index 00000000000..ff43206a3fd
--- /dev/null
+++ b/tests/ui/simd/simd-bitmask-notpow2.rs
@@ -0,0 +1,90 @@
+//@run-pass
+// SEGFAULTS on LLVM 17. This should be merged into `simd-bitmask` once we require LLVM 18.
+//@ min-llvm-version: 18
+// FIXME: broken codegen on big-endian (https://github.com/rust-lang/rust/issues/127205)
+//@ ignore-endian-big
+#![feature(repr_simd, intrinsics)]
+
+extern "rust-intrinsic" {
+    fn simd_bitmask<T, U>(v: T) -> U;
+    fn simd_select_bitmask<T, U>(m: T, a: U, b: U) -> U;
+}
+
+fn main() {
+    // Non-power-of-2 multi-byte mask.
+    #[repr(simd, packed)]
+    #[allow(non_camel_case_types)]
+    #[derive(Copy, Clone, Debug, PartialEq)]
+    struct i32x10([i32; 10]);
+    impl i32x10 {
+        fn splat(x: i32) -> Self {
+            Self([x; 10])
+        }
+    }
+    unsafe {
+        let mask = i32x10([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]);
+        let mask_bits = if cfg!(target_endian = "little") { 0b0101001011 } else { 0b1101001010 };
+        let mask_bytes =
+            if cfg!(target_endian = "little") { [0b01001011, 0b01] } else { [0b11, 0b01001010] };
+
+        let bitmask1: u16 = simd_bitmask(mask);
+        let bitmask2: [u8; 2] = simd_bitmask(mask);
+        assert_eq!(bitmask1, mask_bits);
+        assert_eq!(bitmask2, mask_bytes);
+
+        let selected1 = simd_select_bitmask::<u16, _>(
+            mask_bits,
+            i32x10::splat(!0), // yes
+            i32x10::splat(0),  // no
+        );
+        let selected2 = simd_select_bitmask::<[u8; 2], _>(
+            mask_bytes,
+            i32x10::splat(!0), // yes
+            i32x10::splat(0),  // no
+        );
+        assert_eq!(selected1, mask);
+        assert_eq!(selected2, mask);
+    }
+
+    // Test for a mask where the next multiple of 8 is not a power of two.
+    #[repr(simd, packed)]
+    #[allow(non_camel_case_types)]
+    #[derive(Copy, Clone, Debug, PartialEq)]
+    struct i32x20([i32; 20]);
+    impl i32x20 {
+        fn splat(x: i32) -> Self {
+            Self([x; 20])
+        }
+    }
+    unsafe {
+        let mask = i32x20([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0, 0, 0, 0, !0, !0, !0, !0, !0, !0, !0]);
+        let mask_bits = if cfg!(target_endian = "little") {
+            0b11111110000101001011
+        } else {
+            0b11010010100001111111
+        };
+        let mask_bytes = if cfg!(target_endian = "little") {
+            [0b01001011, 0b11100001, 0b1111]
+        } else {
+            [0b1101, 0b00101000, 0b01111111]
+        };
+
+        let bitmask1: u32 = simd_bitmask(mask);
+        let bitmask2: [u8; 3] = simd_bitmask(mask);
+        assert_eq!(bitmask1, mask_bits);
+        assert_eq!(bitmask2, mask_bytes);
+
+        let selected1 = simd_select_bitmask::<u32, _>(
+            mask_bits,
+            i32x20::splat(!0), // yes
+            i32x20::splat(0),  // no
+        );
+        let selected2 = simd_select_bitmask::<[u8; 3], _>(
+            mask_bytes,
+            i32x20::splat(!0), // yes
+            i32x20::splat(0),  // no
+        );
+        assert_eq!(selected1, mask);
+        assert_eq!(selected2, mask);
+    }
+}
diff --git a/tests/ui/simd/simd-bitmask.rs b/tests/ui/simd/simd-bitmask.rs
index 4a7c3bc7750..82f73fca951 100644
--- a/tests/ui/simd/simd-bitmask.rs
+++ b/tests/ui/simd/simd-bitmask.rs
@@ -1,5 +1,4 @@
 //@run-pass
-//@ignore-endian-big behavior of simd_select_bitmask is endian-specific
 #![feature(repr_simd, intrinsics)]
 
 extern "rust-intrinsic" {
@@ -17,36 +16,58 @@ fn main() {
         let i: u8 = simd_bitmask(v);
         let a: [u8; 1] = simd_bitmask(v);
 
-        assert_eq!(i, 0b0101);
-        assert_eq!(a, [0b0101]);
+        if cfg!(target_endian = "little") {
+            assert_eq!(i, 0b0101);
+            assert_eq!(a, [0b0101]);
+        } else {
+            assert_eq!(i, 0b1010);
+            assert_eq!(a, [0b1010]);
+        }
 
         let v = Simd::<i8, 16>([0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0]);
         let i: u16 = simd_bitmask(v);
         let a: [u8; 2] = simd_bitmask(v);
 
-        assert_eq!(i, 0b0101000000001100);
-        assert_eq!(a, [0b1100, 0b01010000]);
+        if cfg!(target_endian = "little") {
+            assert_eq!(i, 0b0101000000001100);
+            assert_eq!(a, [0b00001100, 0b01010000]);
+        } else {
+            assert_eq!(i, 0b0011000000001010);
+            assert_eq!(a, [0b00110000, 0b00001010]);
+        }
     }
 
     unsafe {
-        let a = Simd::<i32, 8>([0, 1, 2, 3, 4, 5, 6, 7]);
-        let b = Simd::<i32, 8>([8, 9, 10, 11, 12, 13, 14, 15]);
-        let e = [0, 9, 2, 11, 12, 13, 14, 15];
+        let a = Simd::<i32, 4>([0, 1, 2, 3]);
+        let b = Simd::<i32, 4>([8, 9, 10, 11]);
+        let e = [0, 9, 2, 11];
 
-        let r = simd_select_bitmask(0b0101u8, a, b);
+        let mask = if cfg!(target_endian = "little") { 0b0101u8 } else { 0b1010u8 };
+        let r = simd_select_bitmask(mask, a, b);
         assert_eq!(r.0, e);
 
-        let r = simd_select_bitmask([0b0101u8], a, b);
+        let mask = if cfg!(target_endian = "little") { [0b0101u8] } else { [0b1010u8] };
+        let r = simd_select_bitmask(mask, a, b);
         assert_eq!(r.0, e);
 
         let a = Simd::<i32, 16>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
         let b = Simd::<i32, 16>([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]);
         let e = [16, 17, 2, 3, 20, 21, 22, 23, 24, 25, 26, 27, 12, 29, 14, 31];
 
-        let r = simd_select_bitmask(0b0101000000001100u16, a, b);
+        let mask = if cfg!(target_endian = "little") {
+            0b0101000000001100u16
+        } else {
+            0b0011000000001010u16
+        };
+        let r = simd_select_bitmask(mask, a, b);
         assert_eq!(r.0, e);
 
-        let r = simd_select_bitmask([0b1100u8, 0b01010000u8], a, b);
+        let mask = if cfg!(target_endian = "little") {
+            [0b00001100u8, 0b01010000u8]
+        } else {
+            [0b00110000u8, 0b00001010u8]
+        };
+        let r = simd_select_bitmask(mask, a, b);
         assert_eq!(r.0, e);
     }
 }
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr
index 6bbd81ae3e1..c01b2ccd163 100644
--- a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr
+++ b/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr
@@ -3,14 +3,14 @@ error[E0391]: cycle detected when computing layout of `Foo`
    = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`...
    = note: ...which again requires computing layout of `Foo`, completing the cycle
 note: cycle used when const-evaluating + checking `_`
-  --> $DIR/stack-overflow-trait-infer-98842.rs:15:1
+  --> $DIR/stack-overflow-trait-infer-98842.rs:14:1
    |
 LL | const _: *const Foo = 0 as _;
    | ^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/stack-overflow-trait-infer-98842.rs:15:1
+  --> $DIR/stack-overflow-trait-infer-98842.rs:14:1
    |
 LL | const _: *const Foo = 0 as _;
    | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr
index 6bbd81ae3e1..c01b2ccd163 100644
--- a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr
+++ b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr
@@ -3,14 +3,14 @@ error[E0391]: cycle detected when computing layout of `Foo`
    = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`...
    = note: ...which again requires computing layout of `Foo`, completing the cycle
 note: cycle used when const-evaluating + checking `_`
-  --> $DIR/stack-overflow-trait-infer-98842.rs:15:1
+  --> $DIR/stack-overflow-trait-infer-98842.rs:14:1
    |
 LL | const _: *const Foo = 0 as _;
    | ^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/stack-overflow-trait-infer-98842.rs:15:1
+  --> $DIR/stack-overflow-trait-infer-98842.rs:14:1
    |
 LL | const _: *const Foo = 0 as _;
    | ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.rs b/tests/ui/sized/stack-overflow-trait-infer-98842.rs
index be4807b2e4a..8a958870b0e 100644
--- a/tests/ui/sized/stack-overflow-trait-infer-98842.rs
+++ b/tests/ui/sized/stack-overflow-trait-infer-98842.rs
@@ -3,8 +3,7 @@
 //@ check-fail
 //@ edition:2021
 //@ stderr-per-bitwidth
-//@ ignore-endian-big
-//~^^^^^^ ERROR cycle detected when computing layout of `Foo`
+//~^^^^^ ERROR cycle detected when computing layout of `Foo`
 
 // If the inner `Foo` is named through an associated type,
 // the "infinite size" error does not occur.
diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr
index f0dea66f612..89c67719b5a 100644
--- a/tests/ui/span/issue-34264.stderr
+++ b/tests/ui/span/issue-34264.stderr
@@ -54,16 +54,18 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/issue-34264.rs:7:5
    |
 LL |     foo(Some(42), 2, "");
-   |     ^^^            ----
-   |                    | |
-   |                    | unexpected argument of type `&'static str`
-   |                    help: remove the extra argument
+   |     ^^^              -- unexpected argument of type `&'static str`
    |
 note: function defined here
   --> $DIR/issue-34264.rs:1:4
    |
 LL | fn foo(Option<i32>, String) {}
    |    ^^^ -----------  ------
+help: remove the extra argument
+   |
+LL -     foo(Some(42), 2, "");
+LL +     foo(Some(42), 2);
+   |
 
 error[E0308]: mismatched types
   --> $DIR/issue-34264.rs:8:13
@@ -83,16 +85,18 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/issue-34264.rs:10:5
    |
 LL |     bar(1, 2, 3);
-   |     ^^^     ---
-   |             | |
-   |             | unexpected argument of type `{integer}`
-   |             help: remove the extra argument
+   |     ^^^       - unexpected argument of type `{integer}`
    |
 note: function defined here
   --> $DIR/issue-34264.rs:3:4
    |
 LL | fn bar(x, y: usize) {}
    |    ^^^ -  --------
+help: remove the extra argument
+   |
+LL -     bar(1, 2, 3);
+LL +     bar(1, 2);
+   |
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/structs/structure-constructor-type-mismatch.stderr b/tests/ui/structs/structure-constructor-type-mismatch.stderr
index 63dda459396..cb957487347 100644
--- a/tests/ui/structs/structure-constructor-type-mismatch.stderr
+++ b/tests/ui/structs/structure-constructor-type-mismatch.stderr
@@ -2,55 +2,67 @@ error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:17:12
    |
 LL |         x: 1,
-   |            ^
-   |            |
-   |            expected `f32`, found integer
-   |            help: use a float literal: `1.0`
+   |            ^ expected `f32`, found integer
+   |
+help: use a float literal
+   |
+LL |         x: 1.0,
+   |             ++
 
 error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:20:12
    |
 LL |         y: 2,
-   |            ^
-   |            |
-   |            expected `f32`, found integer
-   |            help: use a float literal: `2.0`
+   |            ^ expected `f32`, found integer
+   |
+help: use a float literal
+   |
+LL |         y: 2.0,
+   |             ++
 
 error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:26:12
    |
 LL |         x: 3,
-   |            ^
-   |            |
-   |            expected `f32`, found integer
-   |            help: use a float literal: `3.0`
+   |            ^ expected `f32`, found integer
+   |
+help: use a float literal
+   |
+LL |         x: 3.0,
+   |             ++
 
 error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:29:12
    |
 LL |         y: 4,
-   |            ^
-   |            |
-   |            expected `f32`, found integer
-   |            help: use a float literal: `4.0`
+   |            ^ expected `f32`, found integer
+   |
+help: use a float literal
+   |
+LL |         y: 4.0,
+   |             ++
 
 error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:35:12
    |
 LL |         x: 5,
-   |            ^
-   |            |
-   |            expected `f32`, found integer
-   |            help: use a float literal: `5.0`
+   |            ^ expected `f32`, found integer
+   |
+help: use a float literal
+   |
+LL |         x: 5.0,
+   |             ++
 
 error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:42:12
    |
 LL |         x: 7,
-   |            ^
-   |            |
-   |            expected `f32`, found integer
-   |            help: use a float literal: `7.0`
+   |            ^ expected `f32`, found integer
+   |
+help: use a float literal
+   |
+LL |         x: 7.0,
+   |             ++
 
 error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/structure-constructor-type-mismatch.rs:48:15
@@ -70,19 +82,23 @@ error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:49:12
    |
 LL |         x: 9,
-   |            ^
-   |            |
-   |            expected `f32`, found integer
-   |            help: use a float literal: `9.0`
+   |            ^ expected `f32`, found integer
+   |
+help: use a float literal
+   |
+LL |         x: 9.0,
+   |             ++
 
 error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:50:12
    |
 LL |         y: 10,
-   |            ^^
-   |            |
-   |            expected `f32`, found integer
-   |            help: use a float literal: `10.0`
+   |            ^^ expected `f32`, found integer
+   |
+help: use a float literal
+   |
+LL |         y: 10.0,
+   |              ++
 
 error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/structure-constructor-type-mismatch.rs:54:9
diff --git a/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.fixed b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.fixed
index e072c476c6b..4e562193f0d 100644
--- a/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.fixed
+++ b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.fixed
@@ -3,9 +3,9 @@
 
 trait Trait {}
 
-fn assert_send(ptr: *mut dyn Trait) -> *mut (dyn Trait + Send) {
+fn assert_send() -> *mut (dyn Trait + Send) {
     //~^ ERROR incorrect parentheses around trait bounds
-    ptr as _
+    loop {}
 }
 
 fn foo2(_: &(dyn Trait + Send)) {}
diff --git a/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs
index 88995141426..4a00059400c 100644
--- a/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs
+++ b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs
@@ -3,9 +3,9 @@
 
 trait Trait {}
 
-fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) {
+fn assert_send() -> *mut dyn (Trait + Send) {
     //~^ ERROR incorrect parentheses around trait bounds
-    ptr as _
+    loop {}
 }
 
 fn foo2(_: &dyn (Trait + Send)) {}
diff --git a/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.stderr b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.stderr
index 2d1abe91a1e..c67557fa14f 100644
--- a/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.stderr
+++ b/tests/ui/suggestions/issue-114797-bad-parentheses-dyn-trait.stderr
@@ -1,13 +1,13 @@
 error: incorrect parentheses around trait bounds
-  --> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:6:49
+  --> $DIR/issue-114797-bad-parentheses-dyn-trait.rs:6:30
    |
-LL | fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) {
-   |                                                 ^            ^
+LL | fn assert_send() -> *mut dyn (Trait + Send) {
+   |                              ^            ^
    |
 help: fix the parentheses
    |
-LL - fn assert_send(ptr: *mut dyn Trait) -> *mut dyn (Trait + Send) {
-LL + fn assert_send(ptr: *mut dyn Trait) -> *mut (dyn Trait + Send) {
+LL - fn assert_send() -> *mut dyn (Trait + Send) {
+LL + fn assert_send() -> *mut (dyn Trait + Send) {
    |
 
 error: incorrect parentheses around trait bounds
diff --git a/tests/ui/suggestions/match-ergonomics.stderr b/tests/ui/suggestions/match-ergonomics.stderr
index a3e059e8ac6..2cd43c26ca3 100644
--- a/tests/ui/suggestions/match-ergonomics.stderr
+++ b/tests/ui/suggestions/match-ergonomics.stderr
@@ -17,18 +17,24 @@ LL +         [v] => {},
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/match-ergonomics.rs:8:9
    |
-LL |     match x {
-   |           - help: consider slicing here: `x[..]`
 LL |         [&v] => {},
    |         ^^^^ pattern cannot match with input type `Vec<i32>`
+   |
+help: consider slicing here
+   |
+LL |     match x[..] {
+   |            ++++
 
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/match-ergonomics.rs:20:9
    |
-LL |     match x {
-   |           - help: consider slicing here: `x[..]`
 LL |         [v] => {},
    |         ^^^ pattern cannot match with input type `Vec<i32>`
+   |
+help: consider slicing here
+   |
+LL |     match x[..] {
+   |            ++++
 
 error[E0308]: mismatched types
   --> $DIR/match-ergonomics.rs:29:9
diff --git a/tests/ui/suggestions/parenthesized-deref-suggestion.stderr b/tests/ui/suggestions/parenthesized-deref-suggestion.stderr
index 9f185f5dd52..29e973b3a17 100644
--- a/tests/ui/suggestions/parenthesized-deref-suggestion.stderr
+++ b/tests/ui/suggestions/parenthesized-deref-suggestion.stderr
@@ -4,19 +4,21 @@ error[E0609]: no field `opts` on type `*const Session`
 LL |     (sess as *const Session).opts;
    |                              ^^^^ unknown field
    |
-help: `(sess as *const Session)` is a raw pointer; try dereferencing it
+help: the value is a raw pointer; try dereferencing it
    |
 LL |     (*(sess as *const Session)).opts;
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |     ++                        +
 
 error[E0609]: no field `0` on type `[u32; 1]`
   --> $DIR/parenthesized-deref-suggestion.rs:10:21
    |
 LL |     (x as [u32; 1]).0;
-   |     ----------------^
-   |     |               |
-   |     |               unknown field
-   |     help: instead of using tuple indexing, use array indexing: `(x as [u32; 1])[0]`
+   |                     ^ unknown field
+   |
+help: instead of using tuple indexing, use array indexing
+   |
+LL |     (x as [u32; 1])[0];
+   |                    ~ +
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/pattern-slice-vec.stderr b/tests/ui/suggestions/pattern-slice-vec.stderr
index f69e7de971a..36a9df3f750 100644
--- a/tests/ui/suggestions/pattern-slice-vec.stderr
+++ b/tests/ui/suggestions/pattern-slice-vec.stderr
@@ -2,42 +2,56 @@ error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/pattern-slice-vec.rs:8:12
    |
 LL |     if let [_, _, _] = foo() {}
-   |            ^^^^^^^^^   ----- help: consider slicing here: `foo()[..]`
-   |            |
-   |            pattern cannot match with input type `Vec<i32>`
+   |            ^^^^^^^^^ pattern cannot match with input type `Vec<i32>`
+   |
+help: consider slicing here
+   |
+LL |     if let [_, _, _] = foo()[..] {}
+   |                             ++++
 
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/pattern-slice-vec.rs:12:12
    |
 LL |     if let [] = &foo() {}
-   |            ^^   ------ help: consider slicing here: `&foo()[..]`
-   |            |
-   |            pattern cannot match with input type `Vec<i32>`
+   |            ^^ pattern cannot match with input type `Vec<i32>`
+   |
+help: consider slicing here
+   |
+LL |     if let [] = &foo()[..] {}
+   |                       ++++
 
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/pattern-slice-vec.rs:16:12
    |
 LL |     if let [] = foo() {}
-   |            ^^   ----- help: consider slicing here: `foo()[..]`
-   |            |
-   |            pattern cannot match with input type `Vec<i32>`
+   |            ^^ pattern cannot match with input type `Vec<i32>`
+   |
+help: consider slicing here
+   |
+LL |     if let [] = foo()[..] {}
+   |                      ++++
 
 error[E0529]: expected an array or slice, found `Vec<_>`
   --> $DIR/pattern-slice-vec.rs:23:9
    |
-LL |     match &v {
-   |           -- help: consider slicing here: `&v[..]`
-LL |
 LL |         [5] => {}
    |         ^^^ pattern cannot match with input type `Vec<_>`
+   |
+help: consider slicing here
+   |
+LL |     match &v[..] {
+   |             ++++
 
 error[E0529]: expected an array or slice, found `Vec<{integer}>`
   --> $DIR/pattern-slice-vec.rs:28:9
    |
 LL |     let [..] = vec![1, 2, 3];
-   |         ^^^^   ------------- help: consider slicing here: `vec![1, 2, 3][..]`
-   |         |
-   |         pattern cannot match with input type `Vec<{integer}>`
+   |         ^^^^ pattern cannot match with input type `Vec<{integer}>`
+   |
+help: consider slicing here
+   |
+LL |     let [..] = vec![1, 2, 3][..];
+   |                             ++++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr b/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr
index c28d67604da..cab9bbb72df 100644
--- a/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr
+++ b/tests/ui/suggestions/suppress-consider-slicing-issue-120605.stderr
@@ -2,9 +2,12 @@ error[E0529]: expected an array or slice, found `Vec<Struct>`
   --> $DIR/suppress-consider-slicing-issue-120605.rs:7:16
    |
 LL |         if let [Struct { a: [] }] = &self.a {
-   |                ^^^^^^^^^^^^^^^^^^   ------- help: consider slicing here: `&self.a[..]`
-   |                |
-   |                pattern cannot match with input type `Vec<Struct>`
+   |                ^^^^^^^^^^^^^^^^^^ pattern cannot match with input type `Vec<Struct>`
+   |
+help: consider slicing here
+   |
+LL |         if let [Struct { a: [] }] = &self.a[..] {
+   |                                            ++++
 
 error[E0529]: expected an array or slice, found `Vec<Struct>`
   --> $DIR/suppress-consider-slicing-issue-120605.rs:7:29
diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs
index 03c175a2a49..8c9e222a40d 100644
--- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs
+++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs
@@ -10,6 +10,7 @@
 //@ ignore-wasm no panic or subprocess support
 //@ ignore-emscripten no panic or subprocess support
 //@ ignore-sgx no subprocess support
+//@ ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#127539)
 
 #![cfg(test)]
 
diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr
index 16001b3eecd..4c94518d4d1 100644
--- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr
+++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr
@@ -1,9 +1,9 @@
-thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:34:5:
+thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:35:5:
 assertion `left == right` failed
   left: 2
  right: 4
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:28:5:
+thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:29:5:
 assertion `left == right` failed
   left: 2
  right: 4
diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs
index 77efaf05bbc..c9f6439ef89 100644
--- a/tests/ui/test-attrs/test-panic-abort.rs
+++ b/tests/ui/test-attrs/test-panic-abort.rs
@@ -10,6 +10,7 @@
 //@ ignore-wasm no panic or subprocess support
 //@ ignore-emscripten no panic or subprocess support
 //@ ignore-sgx no subprocess support
+//@ ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#127539)
 
 #![cfg(test)]
 #![feature(test)]
diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout
index f5d14e77da9..25105f38fcf 100644
--- a/tests/ui/test-attrs/test-panic-abort.run.stdout
+++ b/tests/ui/test-attrs/test-panic-abort.run.stdout
@@ -17,7 +17,7 @@ hello, world
 testing123
 ---- it_fails stderr ----
 testing321
-thread 'main' panicked at $DIR/test-panic-abort.rs:39:5:
+thread 'main' panicked at $DIR/test-panic-abort.rs:40:5:
 assertion `left == right` failed
   left: 2
  right: 5
diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
index 445ea2de610..52b488101a8 100644
--- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
+++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
@@ -11,7 +11,7 @@ impl<T, S> Trait<T> for i32 {
     type Assoc = String;
 }
 
-// Should not not trigger suggestion here...
+// Should not trigger suggestion here...
 impl<T, S> Trait<T, S> for () {}
 //~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
 
diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr b/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr
index 38e692521ca..03a4017b3d7 100644
--- a/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr
+++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr
@@ -23,29 +23,29 @@ LL | struct Struct {}
    | ---------------- not a trait
 
 error: function not found in this trait
-  --> $DIR/rustc_must_implement_one_of_misuse.rs:3:31
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:8:34
    |
 LL | #[rustc_must_implement_one_of(a, b)]
-   |                               ^
+   |                                  ^
+
+error: the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:14:1
+   |
+LL | #[rustc_must_implement_one_of(a)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: function not found in this trait
-  --> $DIR/rustc_must_implement_one_of_misuse.rs:3:34
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:3:31
    |
 LL | #[rustc_must_implement_one_of(a, b)]
-   |                                  ^
+   |                               ^
 
 error: function not found in this trait
-  --> $DIR/rustc_must_implement_one_of_misuse.rs:8:34
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:3:34
    |
 LL | #[rustc_must_implement_one_of(a, b)]
    |                                  ^
 
-error: the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
-  --> $DIR/rustc_must_implement_one_of_misuse.rs:14:1
-   |
-LL | #[rustc_must_implement_one_of(a)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: not a function
   --> $DIR/rustc_must_implement_one_of_misuse.rs:26:5
    |
diff --git a/tests/ui/traits/impl-method-mismatch.stderr b/tests/ui/traits/impl-method-mismatch.stderr
index 77d542c729a..db457b77a23 100644
--- a/tests/ui/traits/impl-method-mismatch.stderr
+++ b/tests/ui/traits/impl-method-mismatch.stderr
@@ -10,7 +10,7 @@ note: type in trait
 LL |     fn jumbo(&self, x: &usize) -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected signature `fn(&_, &_) -> usize`
-              found signature `unsafe fn(&_, &_)`
+              found signature `unsafe fn(&_, &_) -> ()`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/issue-35869.stderr b/tests/ui/traits/issue-35869.stderr
index 6d985bdeaf8..503f9cee246 100644
--- a/tests/ui/traits/issue-35869.stderr
+++ b/tests/ui/traits/issue-35869.stderr
@@ -2,10 +2,7 @@ error[E0053]: method `foo` has an incompatible type for trait
   --> $DIR/issue-35869.rs:11:15
    |
 LL |     fn foo(_: fn(u16) -> ()) {}
-   |               ^^^^^^^^^^^^^
-   |               |
-   |               expected `u8`, found `u16`
-   |               help: change the parameter type to match the trait: `fn(u8)`
+   |               ^^^^^^^^^^^^^ expected `u8`, found `u16`
    |
 note: type in trait
   --> $DIR/issue-35869.rs:2:15
@@ -14,15 +11,16 @@ LL |     fn foo(_: fn(u8) -> ());
    |               ^^^^^^^^^^^^
    = note: expected signature `fn(fn(u8))`
               found signature `fn(fn(u16))`
+help: change the parameter type to match the trait
+   |
+LL |     fn foo(_: fn(u8)) {}
+   |               ~~~~~~
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/issue-35869.rs:13:15
    |
 LL |     fn bar(_: Option<u16>) {}
-   |               ^^^^^^^^^^^
-   |               |
-   |               expected `u8`, found `u16`
-   |               help: change the parameter type to match the trait: `Option<u8>`
+   |               ^^^^^^^^^^^ expected `u8`, found `u16`
    |
 note: type in trait
   --> $DIR/issue-35869.rs:3:15
@@ -31,15 +29,16 @@ LL |     fn bar(_: Option<u8>);
    |               ^^^^^^^^^^
    = note: expected signature `fn(Option<u8>)`
               found signature `fn(Option<u16>)`
+help: change the parameter type to match the trait
+   |
+LL |     fn bar(_: Option<u8>) {}
+   |               ~~~~~~~~~~
 
 error[E0053]: method `baz` has an incompatible type for trait
   --> $DIR/issue-35869.rs:15:15
    |
 LL |     fn baz(_: (u16, u16)) {}
-   |               ^^^^^^^^^^
-   |               |
-   |               expected `u8`, found `u16`
-   |               help: change the parameter type to match the trait: `(u8, u16)`
+   |               ^^^^^^^^^^ expected `u8`, found `u16`
    |
 note: type in trait
   --> $DIR/issue-35869.rs:4:15
@@ -48,15 +47,16 @@ LL |     fn baz(_: (u8, u16));
    |               ^^^^^^^^^
    = note: expected signature `fn((u8, _))`
               found signature `fn((u16, _))`
+help: change the parameter type to match the trait
+   |
+LL |     fn baz(_: (u8, u16)) {}
+   |               ~~~~~~~~~
 
 error[E0053]: method `qux` has an incompatible type for trait
   --> $DIR/issue-35869.rs:17:17
    |
 LL |     fn qux() -> u16 { 5u16 }
-   |                 ^^^
-   |                 |
-   |                 expected `u8`, found `u16`
-   |                 help: change the output type to match the trait: `u8`
+   |                 ^^^ expected `u8`, found `u16`
    |
 note: type in trait
   --> $DIR/issue-35869.rs:5:17
@@ -65,6 +65,10 @@ LL |     fn qux() -> u8;
    |                 ^^
    = note: expected signature `fn() -> u8`
               found signature `fn() -> u16`
+help: change the output type to match the trait
+   |
+LL |     fn qux() -> u8 { 5u16 }
+   |                 ~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs
index ddbbcdd0529..d9c422e6f70 100644
--- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs
+++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs
@@ -1,9 +1,5 @@
 //@ build-fail
 //@ compile-flags: -Zinline-mir=no
-//@ error-pattern: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
-//@ error-pattern: function cannot return without recursing
-//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
-//@ ignore-compare-mode-next-solver (hangs)
 
 // Regression test for #91949.
 // This hanged *forever* on 1.56, fixed by #90423.
@@ -22,10 +18,12 @@ impl<T, I: Iterator<Item = T>> Iterator for IteratorOfWrapped<T, I> {
 }
 
 fn recurse<T>(elements: T) -> Vec<char>
+//~^ WARN function cannot return without recursing
 where
     T: Iterator<Item = ()>,
 {
     recurse(IteratorOfWrapped(elements).map(|t| t.0))
+    //~^ ERROR reached the type-length limit
 }
 
 fn main() {
diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr
index c4324f0f0a8..c46c78609d2 100644
--- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr
+++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr
@@ -1,7 +1,8 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-91949-hangs-on-recursion.rs:24:1
+  --> $DIR/issue-91949-hangs-on-recursion.rs:20:1
    |
 LL | / fn recurse<T>(elements: T) -> Vec<char>
+LL | |
 LL | | where
 LL | |     T: Iterator<Item = ()>,
    | |___________________________^ cannot return without recursing
@@ -12,19 +13,14 @@ LL |       recurse(IteratorOfWrapped(elements).map(|t| t.0))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error[E0275]: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
+error: reached the type-length limit while instantiating `<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), ...>, ...>> as Iterator>::map::<..., ...>`
+  --> $DIR/issue-91949-hangs-on-recursion.rs:25:13
    |
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`)
-note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator`
-  --> $DIR/issue-91949-hangs-on-recursion.rs:17:32
+LL |     recurse(IteratorOfWrapped(elements).map(|t| t.0))
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | impl<T, I: Iterator<Item = T>> Iterator for IteratorOfWrapped<T, I> {
-   |                     --------   ^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     unsatisfied trait bound introduced here
-   = note: 256 redundant requirements hidden
-   = note: required for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), std::iter::Empty<()>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>` to implement `Iterator`
+   = help: consider adding a `#![type_length_limit="27262965"]` attribute to your crate
+   = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type.txt'
 
 error: aborting due to 1 previous error; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr
index 83d520341bc..e47da338736 100644
--- a/tests/ui/traits/next-solver/async.fail.stderr
+++ b/tests/ui/traits/next-solver/async.fail.stderr
@@ -1,11 +1,13 @@
-error[E0271]: type mismatch resolving `<{async block@$DIR/async.rs:12:17: 12:22} as Future>::Output == i32`
+error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
   --> $DIR/async.rs:12:17
    |
 LL |     needs_async(async {});
-   |     ----------- ^^^^^^^^ types differ
+   |     ----------- ^^^^^^^^ expected `()`, found `i32`
    |     |
    |     required by a bound introduced by this call
    |
+   = note: expected unit type `()`
+                   found type `i32`
 note: required by a bound in `needs_async`
   --> $DIR/async.rs:8:31
    |
diff --git a/tests/ui/traits/next-solver/async.rs b/tests/ui/traits/next-solver/async.rs
index 129e4cfaa02..fded7743547 100644
--- a/tests/ui/traits/next-solver/async.rs
+++ b/tests/ui/traits/next-solver/async.rs
@@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {}
 #[cfg(fail)]
 fn main() {
     needs_async(async {});
-    //[fail]~^ ERROR type mismatch
+    //[fail]~^ ERROR expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
 }
 
 #[cfg(pass)]
diff --git a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr
index e0b23bd8110..c2029a5a1c8 100644
--- a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr
+++ b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr
@@ -17,10 +17,6 @@ note: required by a bound in `is_send`
    |
 LL |     fn is_send(_: impl Send) {}
    |                        ^^^^ required by this bound in `is_send`
-help: consider dereferencing here
-   |
-LL |     is_send(*foo());
-   |             +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/next-solver/more-object-bound.stderr b/tests/ui/traits/next-solver/more-object-bound.stderr
index 8cc2a51ee2b..043cbdff9ab 100644
--- a/tests/ui/traits/next-solver/more-object-bound.stderr
+++ b/tests/ui/traits/next-solver/more-object-bound.stderr
@@ -1,9 +1,22 @@
 error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
   --> $DIR/more-object-bound.rs:12:5
    |
+LL | fn transmute<A, B>(x: A) -> B {
+   |              -  -
+   |              |  |
+   |              |  expected type parameter
+   |              |  found type parameter
+   |              found type parameter
+   |              expected type parameter
 LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `A`, found type parameter `B`
    |
+   = note: expected type parameter `A`
+              found type parameter `B`
+   = 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
+   = 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
    = note: required because it appears within the type `dyn Trait<A = A, B = B>`
 note: required by a bound in `foo`
   --> $DIR/more-object-bound.rs:18:8
diff --git a/tests/ui/traits/next-solver/typeck/receiver-self-ty-check-eq.rs b/tests/ui/traits/next-solver/typeck/receiver-self-ty-check-eq.rs
new file mode 100644
index 00000000000..f8c8a17b7e5
--- /dev/null
+++ b/tests/ui/traits/next-solver/typeck/receiver-self-ty-check-eq.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// Fixes a regression in `receiver_is_valid` in wfcheck where we were using
+// `InferCtxt::can_eq` instead of processing alias-relate goals, leading to false
+// positives, not deref'ing enough steps to check the receiver is valid.
+
+trait Mirror {
+    type Mirror: ?Sized;
+}
+impl<T: ?Sized> Mirror for T {
+    type Mirror = T;
+}
+
+trait Foo {
+    fn foo(&self) {}
+}
+
+impl Foo for <() as Mirror>::Mirror {
+    fn foo(&self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/traits/upcast_soundness_bug.rs b/tests/ui/traits/upcast_soundness_bug.rs
index 95b48cdf379..5eaa58f7efe 100644
--- a/tests/ui/traits/upcast_soundness_bug.rs
+++ b/tests/ui/traits/upcast_soundness_bug.rs
@@ -1,7 +1,8 @@
 #![feature(trait_upcasting)]
-//@ known-bug: #120222
-//@ check-pass
-//! This will segfault at runtime.
+//@ check-fail
+//
+// issue: <https://github.com/rust-lang/rust/pull/120222>
+//! This would segfault at runtime.
 
 pub trait SupSupA {
     fn method(&self) {}
@@ -56,6 +57,7 @@ pub fn user2() -> &'static dyn Trait<u8, u16> {
 fn main() {
     let p: *const dyn Trait<u8, u8> = &();
     let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
+    //~^ error: mismatched types
     let p = p as *const dyn Super<u16>; // <- this upcast accesses improper vtable entry
     // accessing from L__unnamed_2 the position for the 'Super<u16> vtable (pointer)',
     // thus reading 'null pointer for missing_method'
diff --git a/tests/ui/traits/upcast_soundness_bug.stderr b/tests/ui/traits/upcast_soundness_bug.stderr
new file mode 100644
index 00000000000..5864abcdb41
--- /dev/null
+++ b/tests/ui/traits/upcast_soundness_bug.stderr
@@ -0,0 +1,13 @@
+error[E0308]: mismatched types
+  --> $DIR/upcast_soundness_bug.rs:59:13
+   |
+LL |     let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
+   |
+   = note: expected trait object `dyn Trait<u8, u8>`
+              found trait object `dyn Trait<u8, u16>`
+   = help: `dyn Trait<u8, u16>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/wrong-mul-method-signature.stderr b/tests/ui/traits/wrong-mul-method-signature.stderr
index 91162cbc123..e30b61622ae 100644
--- a/tests/ui/traits/wrong-mul-method-signature.stderr
+++ b/tests/ui/traits/wrong-mul-method-signature.stderr
@@ -2,37 +2,40 @@ error[E0053]: method `mul` has an incompatible type for trait
   --> $DIR/wrong-mul-method-signature.rs:16:21
    |
 LL |     fn mul(self, s: &f64) -> Vec1 {
-   |                     ^^^^
-   |                     |
-   |                     expected `f64`, found `&f64`
-   |                     help: change the parameter type to match the trait: `f64`
+   |                     ^^^^ expected `f64`, found `&f64`
    |
    = note: expected signature `fn(Vec1, _) -> Vec1`
               found signature `fn(Vec1, &_) -> Vec1`
+help: change the parameter type to match the trait
+   |
+LL |     fn mul(self, s: f64) -> Vec1 {
+   |                     ~~~
 
 error[E0053]: method `mul` has an incompatible type for trait
   --> $DIR/wrong-mul-method-signature.rs:33:21
    |
 LL |     fn mul(self, s: f64) -> Vec2 {
-   |                     ^^^
-   |                     |
-   |                     expected `Vec2`, found `f64`
-   |                     help: change the parameter type to match the trait: `Vec2`
+   |                     ^^^ expected `Vec2`, found `f64`
    |
    = note: expected signature `fn(Vec2, Vec2) -> f64`
               found signature `fn(Vec2, f64) -> Vec2`
+help: change the parameter type to match the trait
+   |
+LL |     fn mul(self, s: Vec2) -> Vec2 {
+   |                     ~~~~
 
 error[E0053]: method `mul` has an incompatible type for trait
   --> $DIR/wrong-mul-method-signature.rs:52:29
    |
 LL |     fn mul(self, s: f64) -> f64 {
-   |                             ^^^
-   |                             |
-   |                             expected `i32`, found `f64`
-   |                             help: change the output type to match the trait: `i32`
+   |                             ^^^ expected `i32`, found `f64`
    |
    = note: expected signature `fn(Vec3, _) -> i32`
               found signature `fn(Vec3, _) -> f64`
+help: change the output type to match the trait
+   |
+LL |     fn mul(self, s: f64) -> i32 {
+   |                             ~~~
 
 error[E0308]: mismatched types
   --> $DIR/wrong-mul-method-signature.rs:63:45
diff --git a/tests/ui/try-block/try-block-type-error.stderr b/tests/ui/try-block/try-block-type-error.stderr
index 3e9a584a551..2cdb5fdee79 100644
--- a/tests/ui/try-block/try-block-type-error.stderr
+++ b/tests/ui/try-block/try-block-type-error.stderr
@@ -2,10 +2,12 @@ error[E0271]: type mismatch resolving `<Option<f32> as Try>::Output == {integer}
   --> $DIR/try-block-type-error.rs:10:9
    |
 LL |         42
-   |         ^^
-   |         |
-   |         expected `f32`, found integer
-   |         help: use a float literal: `42.0`
+   |         ^^ expected `f32`, found integer
+   |
+help: use a float literal
+   |
+LL |         42.0
+   |           ++
 
 error[E0271]: type mismatch resolving `<Option<i32> as Try>::Output == ()`
   --> $DIR/try-block-type-error.rs:16:5
diff --git a/tests/ui/tuple/wrong_argument_ice-4.stderr b/tests/ui/tuple/wrong_argument_ice-4.stderr
index 3c7d6699be2..10191faf7bf 100644
--- a/tests/ui/tuple/wrong_argument_ice-4.stderr
+++ b/tests/ui/tuple/wrong_argument_ice-4.stderr
@@ -6,16 +6,21 @@ LL |       (|| {})(|| {
 LL | |
 LL | |         let b = 1;
 LL | |     });
-   | |     -
-   | |     |
-   | |_____unexpected argument of type `{closure@$DIR/wrong_argument_ice-4.rs:2:13: 2:15}`
-   |       help: remove the extra argument
+   | |_____- unexpected argument of type `{closure@$DIR/wrong_argument_ice-4.rs:2:13: 2:15}`
    |
 note: closure defined here
   --> $DIR/wrong_argument_ice-4.rs:2:6
    |
 LL |     (|| {})(|| {
    |      ^^
+help: remove the extra argument
+   |
+LL -     (|| {})(|| {
+LL -
+LL -         let b = 1;
+LL -     });
+LL +     (|| {})();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr
index e992d059daf..09efd7a9e7e 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr
+++ b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr
@@ -8,7 +8,7 @@ LL |     fn bar(self: Bar<u32>) {
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
 error[E0307]: invalid `self` parameter type: `&Bar<u32>`
-  --> $DIR/method_resolution3.rs:21:18
+  --> $DIR/method_resolution3.rs:20:18
    |
 LL |     fn baz(self: &Bar<u32>) {
    |                  ^^^^^^^^^
diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr
index 9272017cdf5..09efd7a9e7e 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr
+++ b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr
@@ -1,15 +1,21 @@
-error[E0271]: type mismatch resolving `Foo == u32`
+error[E0307]: invalid `self` parameter type: `Bar<u32>`
   --> $DIR/method_resolution3.rs:16:18
    |
 LL |     fn bar(self: Bar<u32>) {
-   |                  ^^^^^^^^ types differ
+   |                  ^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
-error[E0271]: type mismatch resolving `Foo == u32`
-  --> $DIR/method_resolution3.rs:21:18
+error[E0307]: invalid `self` parameter type: `&Bar<u32>`
+  --> $DIR/method_resolution3.rs:20:18
    |
 LL |     fn baz(self: &Bar<u32>) {
-   |                  ^^^^^^^^^ types differ
+   |                  ^^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0307`.
diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.rs b/tests/ui/type-alias-impl-trait/method_resolution3.rs
index 447f3144b82..0e6176bfe03 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution3.rs
+++ b/tests/ui/type-alias-impl-trait/method_resolution3.rs
@@ -14,13 +14,11 @@ struct Bar<T>(T);
 
 impl Bar<Foo> {
     fn bar(self: Bar<u32>) {
-        //[current]~^ ERROR: invalid `self` parameter
-        //[next]~^^ ERROR: type mismatch resolving `Foo == u32`
+        //~^ ERROR: invalid `self` parameter
         self.foo()
     }
     fn baz(self: &Bar<u32>) {
-        //[current]~^ ERROR: invalid `self` parameter
-        //[next]~^^ ERROR: type mismatch resolving `Foo == u32`
+        //~^ ERROR: invalid `self` parameter
         self.foo()
     }
 }
diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr
index 3a2ca18f890..8ffdb21f251 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr
+++ b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr
@@ -8,7 +8,7 @@ LL |     fn foo(self: Bar<Foo>) {
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
 error[E0307]: invalid `self` parameter type: `&Bar<Foo>`
-  --> $DIR/method_resolution4.rs:32:20
+  --> $DIR/method_resolution4.rs:31:20
    |
 LL |     fn foomp(self: &Bar<Foo>) {
    |                    ^^^^^^^^^
diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr
index 33ed2800ebe..8ffdb21f251 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr
+++ b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr
@@ -1,15 +1,21 @@
-error[E0271]: type mismatch resolving `u32 == Foo`
+error[E0307]: invalid `self` parameter type: `Bar<Foo>`
   --> $DIR/method_resolution4.rs:27:18
    |
 LL |     fn foo(self: Bar<Foo>) {
-   |                  ^^^^^^^^ types differ
+   |                  ^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
-error[E0271]: type mismatch resolving `u32 == Foo`
-  --> $DIR/method_resolution4.rs:32:20
+error[E0307]: invalid `self` parameter type: `&Bar<Foo>`
+  --> $DIR/method_resolution4.rs:31:20
    |
 LL |     fn foomp(self: &Bar<Foo>) {
-   |                    ^^^^^^^^^ types differ
+   |                    ^^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0307`.
diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.rs b/tests/ui/type-alias-impl-trait/method_resolution4.rs
index 42ed04b3c30..f33b4e473ae 100644
--- a/tests/ui/type-alias-impl-trait/method_resolution4.rs
+++ b/tests/ui/type-alias-impl-trait/method_resolution4.rs
@@ -25,13 +25,11 @@ impl Bar<Foo> {
 
 impl Bar<u32> {
     fn foo(self: Bar<Foo>) {
-        //[current]~^ ERROR: invalid `self` parameter
-        //[next]~^^ ERROR: type mismatch resolving `u32 == Foo`
+        //~^ ERROR: invalid `self` parameter
         self.bar()
     }
     fn foomp(self: &Bar<Foo>) {
-        //[current]~^ ERROR: invalid `self` parameter
-        //[next]~^^ ERROR: type mismatch resolving `u32 == Foo`
+        //~^ ERROR: invalid `self` parameter
         self.bar()
     }
 }
diff --git a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs
deleted file mode 100644
index 4f9d54737dc..00000000000
--- a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-//@ check-pass
-
-// See https://doc.rust-lang.org/1.77.0/nightly-rustc/rustc_lint/opaque_hidden_inferred_bound/static.OPAQUE_HIDDEN_INFERRED_BOUND.html#example
-
-#![feature(type_alias_impl_trait)]
-#![allow(dead_code)]
-
-trait Duh {}
-
-impl Duh for i32 {}
-
-trait Trait {
-    type Assoc: Duh;
-}
-
-impl<R: Duh, F: FnMut() -> R> Trait for F {
-    type Assoc = R;
-}
-
-type Sendable = impl Send;
-
-type Foo = impl Trait<Assoc = Sendable>;
-                   //~^ WARNING opaque type `Foo` does not satisfy its associated type bounds
-
-fn foo() -> Foo {
-    || 42
-}
-
-fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr
deleted file mode 100644
index 68def454c7f..00000000000
--- a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-warning: opaque type `Foo` does not satisfy its associated type bounds
-  --> $DIR/tait-in-function-return-type-issue-101903.rs:22:23
-   |
-LL |     type Assoc: Duh;
-   |                 --- this associated type bound is unsatisfied for `Sendable`
-...
-LL | type Foo = impl Trait<Assoc = Sendable>;
-   |                       ^^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(opaque_hidden_inferred_bound)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/type-alias-impl-trait/unnameable_type.stderr b/tests/ui/type-alias-impl-trait/unnameable_type.stderr
index f567b01d29a..5b331c5660d 100644
--- a/tests/ui/type-alias-impl-trait/unnameable_type.stderr
+++ b/tests/ui/type-alias-impl-trait/unnameable_type.stderr
@@ -5,10 +5,7 @@ LL | type MyPrivate = impl Sized;
    |                  ---------- the found opaque type
 LL | impl Trait for u32 {
 LL |     fn dont_define_this(private: MyPrivate) {
-   |                                  ^^^^^^^^^
-   |                                  |
-   |                                  expected `Private`, found opaque type
-   |                                  help: change the parameter type to match the trait: `Private`
+   |                                  ^^^^^^^^^ expected `Private`, found opaque type
    |
 note: type in trait
   --> $DIR/unnameable_type.rs:10:39
@@ -17,6 +14,10 @@ LL |         fn dont_define_this(_private: Private) {}
    |                                       ^^^^^^^
    = note: expected signature `fn(Private)`
               found signature `fn(MyPrivate)`
+help: change the parameter type to match the trait
+   |
+LL |     fn dont_define_this(private: Private) {
+   |                                  ~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type/subtyping-opaque-type.rs b/tests/ui/type/subtyping-opaque-type.rs
deleted file mode 100644
index e17114a3647..00000000000
--- a/tests/ui/type/subtyping-opaque-type.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//@ check-pass
-//@ compile-flags: -Zvalidate-mir
-trait Duh {}
-
-impl Duh for i32 {}
-
-trait Trait {
-    type Assoc: Duh;
-}
-
-impl<R: Duh, F: FnMut() -> R> Trait for F {
-    type Assoc = R;
-}
-
-fn foo() -> impl Trait<Assoc = impl Send> {
-    || 42
-}
-
-fn main() {}
diff --git a/tests/ui/type/type-ascription-instead-of-initializer.stderr b/tests/ui/type/type-ascription-instead-of-initializer.stderr
index efa917334bf..224ff6e7404 100644
--- a/tests/ui/type/type-ascription-instead-of-initializer.stderr
+++ b/tests/ui/type/type-ascription-instead-of-initializer.stderr
@@ -11,13 +11,15 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/type-ascription-instead-of-initializer.rs:2:12
    |
 LL |     let x: Vec::with_capacity(10, 20);
-   |            ^^^^^^^^^^^^^^^^^^   ----
-   |                                 | |
-   |                                 | unexpected argument of type `{integer}`
-   |                                 help: remove the extra argument
+   |            ^^^^^^^^^^^^^^^^^^     -- unexpected argument of type `{integer}`
    |
 note: associated function defined here
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+help: remove the extra argument
+   |
+LL -     let x: Vec::with_capacity(10, 20);
+LL +     let x: Vec::with_capacity(10);
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/type/type-parameter-defaults-referencing-Self.stderr b/tests/ui/type/type-parameter-defaults-referencing-Self.stderr
index 16d08b26722..c81405f03f8 100644
--- a/tests/ui/type/type-parameter-defaults-referencing-Self.stderr
+++ b/tests/ui/type/type-parameter-defaults-referencing-Self.stderr
@@ -5,9 +5,13 @@ LL | trait Foo<T=Self> {
    | ----------------- type parameter `T` must be specified for this
 ...
 LL | fn foo(x: &dyn Foo) { }
-   |                ^^^ help: set the type parameter to the desired type: `Foo<T>`
+   |                ^^^
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
+help: set the type parameter to the desired type
+   |
+LL | fn foo(x: &dyn Foo<T>) { }
+   |                   +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type_length_limit.rs b/tests/ui/type_length_limit.rs
index c60f1be06c6..d6937481a15 100644
--- a/tests/ui/type_length_limit.rs
+++ b/tests/ui/type_length_limit.rs
@@ -1,7 +1,6 @@
 //@ build-fail
-//@ error-pattern: reached the type-length limit while instantiating
 //@ compile-flags: -Copt-level=0
-//@ normalize-stderr-test: ".nll/" -> "/"
+//~^^ ERROR reached the type-length limit
 
 // Test that the type length limit can be changed.
 // The exact type depends on optimizations, so disable them.
@@ -31,4 +30,5 @@ pub struct G<T, K>(std::marker::PhantomData::<(T, K)>);
 
 fn main() {
     drop::<Option<A>>(None);
+    //~^ ERROR reached the type-length limit
 }
diff --git a/tests/ui/type_length_limit.stderr b/tests/ui/type_length_limit.stderr
index 32290a2f5bf..83353547d34 100644
--- a/tests/ui/type_length_limit.stderr
+++ b/tests/ui/type_length_limit.stderr
@@ -1,8 +1,15 @@
 error: reached the type-length limit while instantiating `std::mem::drop::<Option<((((..., ..., ...), ..., ...), ..., ...), ..., ...)>>`
-  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+  --> $DIR/type_length_limit.rs:32:5
    |
-   = help: consider adding a `#![type_length_limit="10"]` attribute to your crate
+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'
 
-error: aborting due to 1 previous error
+error: reached the type-length limit while instantiating `<{closure@rt::lang_start<()>::{closure#0}} as FnMut<()>>::call_mut`
+   |
+   = help: consider adding a `#![type_length_limit="10"]` attribute to your crate
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/typeck/ice-with-expr-not-struct-127332.rs b/tests/ui/typeck/ice-with-expr-not-struct-127332.rs
new file mode 100644
index 00000000000..f3ea360e7e9
--- /dev/null
+++ b/tests/ui/typeck/ice-with-expr-not-struct-127332.rs
@@ -0,0 +1,15 @@
+// Regression test for ICE #127332
+
+// Tests that we do not ICE when a with expr is
+// not a struct but something else like an enum
+
+fn main() {
+    let x = || {
+        enum Foo {
+            A { x: u32 },
+        }
+        let orig = Foo::A { x: 5 };
+        Foo::A { x: 6, ..orig };
+        //~^ ERROR functional record update syntax requires a struct
+    };
+}
diff --git a/tests/ui/typeck/ice-with-expr-not-struct-127332.stderr b/tests/ui/typeck/ice-with-expr-not-struct-127332.stderr
new file mode 100644
index 00000000000..446f49e8639
--- /dev/null
+++ b/tests/ui/typeck/ice-with-expr-not-struct-127332.stderr
@@ -0,0 +1,9 @@
+error[E0436]: functional record update syntax requires a struct
+  --> $DIR/ice-with-expr-not-struct-127332.rs:12:26
+   |
+LL |         Foo::A { x: 6, ..orig };
+   |                          ^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0436`.
diff --git a/tests/ui/typeck/issue-53712.rs b/tests/ui/typeck/issue-53712.rs
index 2353904d79d..49db4fa306a 100644
--- a/tests/ui/typeck/issue-53712.rs
+++ b/tests/ui/typeck/issue-53712.rs
@@ -5,5 +5,5 @@ fn main() {
     arr.0;
     //~^ ERROR no field `0` on type `[{integer}; 5]` [E0609]
     //~| HELP instead of using tuple indexing, use array indexing
-    //~| SUGGESTION arr[0]
+    //~| SUGGESTION [
 }
diff --git a/tests/ui/typeck/issue-53712.stderr b/tests/ui/typeck/issue-53712.stderr
index ec31766324b..ffaf5cde1d7 100644
--- a/tests/ui/typeck/issue-53712.stderr
+++ b/tests/ui/typeck/issue-53712.stderr
@@ -2,10 +2,12 @@ error[E0609]: no field `0` on type `[{integer}; 5]`
   --> $DIR/issue-53712.rs:5:9
    |
 LL |     arr.0;
-   |     ----^
-   |     |   |
-   |     |   unknown field
-   |     help: instead of using tuple indexing, use array indexing: `arr[0]`
+   |         ^ unknown field
+   |
+help: instead of using tuple indexing, use array indexing
+   |
+LL |     arr[0];
+   |        ~ +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/typeck/issue-91328.stderr b/tests/ui/typeck/issue-91328.stderr
index f2f407bcaff..f9016400fd7 100644
--- a/tests/ui/typeck/issue-91328.stderr
+++ b/tests/ui/typeck/issue-91328.stderr
@@ -1,38 +1,46 @@
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/issue-91328.rs:10:12
    |
-LL |     match r {
-   |           - help: consider using `as_deref` here: `r.as_deref()`
-LL |
 LL |         Ok([a, b]) => a + b,
    |            ^^^^^^ pattern cannot match with input type `Vec<i32>`
+   |
+help: consider using `as_deref` here
+   |
+LL |     match r.as_deref() {
+   |            +++++++++++
 
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/issue-91328.rs:20:14
    |
-LL |     match o {
-   |           - help: consider using `as_deref` here: `o.as_deref()`
-LL |
 LL |         Some([a, b]) => a + b,
    |              ^^^^^^ pattern cannot match with input type `Vec<i32>`
+   |
+help: consider using `as_deref` here
+   |
+LL |     match o.as_deref() {
+   |            +++++++++++
 
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/issue-91328.rs:30:9
    |
-LL |     match v {
-   |           - help: consider slicing here: `v[..]`
-LL |
 LL |         [a, b] => a + b,
    |         ^^^^^^ pattern cannot match with input type `Vec<i32>`
+   |
+help: consider slicing here
+   |
+LL |     match v[..] {
+   |            ++++
 
 error[E0529]: expected an array or slice, found `Box<[i32; 2]>`
   --> $DIR/issue-91328.rs:40:14
    |
-LL |     match a {
-   |           - help: consider using `as_deref` here: `a.as_deref()`
-LL |
 LL |         Some([a, b]) => a + b,
    |              ^^^^^^ pattern cannot match with input type `Box<[i32; 2]>`
+   |
+help: consider using `as_deref` here
+   |
+LL |     match a.as_deref() {
+   |            +++++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/typeck/mismatched-map-under-self.stderr b/tests/ui/typeck/mismatched-map-under-self.stderr
index 322bf349f92..59de00a58bb 100644
--- a/tests/ui/typeck/mismatched-map-under-self.stderr
+++ b/tests/ui/typeck/mismatched-map-under-self.stderr
@@ -2,10 +2,7 @@ error[E0053]: method `values` has an incompatible type for trait
   --> $DIR/mismatched-map-under-self.rs:10:15
    |
 LL |     fn values(self) -> Self::Values {
-   |               ^^^^
-   |               |
-   |               expected `&Option<T>`, found `Option<T>`
-   |               help: change the self-receiver type to match the trait: `&self`
+   |               ^^^^ expected `&Option<T>`, found `Option<T>`
    |
 note: type in trait
   --> $DIR/mismatched-map-under-self.rs:4:15
@@ -14,6 +11,10 @@ LL |     fn values(&self) -> Self::Values;
    |               ^^^^^
    = note: expected signature `fn(&Option<_>)`
               found signature `fn(Option<_>)`
+help: change the self-receiver type to match the trait
+   |
+LL |     fn values(&self) -> Self::Values {
+   |               ~~~~~
 
 error[E0631]: type mismatch in function arguments
   --> $DIR/mismatched-map-under-self.rs:12:18
diff --git a/tests/ui/typeck/ptr-null-mutability-suggestions.stderr b/tests/ui/typeck/ptr-null-mutability-suggestions.stderr
index b615d9fb45c..2912977a461 100644
--- a/tests/ui/typeck/ptr-null-mutability-suggestions.stderr
+++ b/tests/ui/typeck/ptr-null-mutability-suggestions.stderr
@@ -2,10 +2,8 @@ error[E0308]: mismatched types
   --> $DIR/ptr-null-mutability-suggestions.rs:9:24
    |
 LL |     expecting_null_mut(ptr::null());
-   |     ------------------ ^^^^^^^^^^^
-   |     |                  |
-   |     |                  types differ in mutability
-   |     |                  help: consider using `core::ptr::null_mut` instead: `core::ptr::null_mut()`
+   |     ------------------ ^^^^^^^^^^^ types differ in mutability
+   |     |
    |     arguments to this function are incorrect
    |
    = note: expected raw pointer `*mut u8`
@@ -15,6 +13,10 @@ note: function defined here
    |
 LL | fn expecting_null_mut(_: *mut u8) {}
    |    ^^^^^^^^^^^^^^^^^^ ----------
+help: consider using `core::ptr::null_mut` instead
+   |
+LL |     expecting_null_mut(core::ptr::null_mut());
+   |                        ~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/typeck/remove-extra-argument.stderr b/tests/ui/typeck/remove-extra-argument.stderr
index 9557c41457d..4bab2959651 100644
--- a/tests/ui/typeck/remove-extra-argument.stderr
+++ b/tests/ui/typeck/remove-extra-argument.stderr
@@ -2,16 +2,18 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/remove-extra-argument.rs:6:5
    |
 LL |     l(vec![], vec![])
-   |     ^       --------
-   |             | |
-   |             | unexpected argument of type `Vec<_>`
-   |             help: remove the extra argument
+   |     ^         ------ unexpected argument of type `Vec<_>`
    |
 note: function defined here
   --> $DIR/remove-extra-argument.rs:3:4
    |
 LL | fn l(_a: Vec<u8>) {}
    |    ^ -----------
+help: remove the extra argument
+   |
+LL -     l(vec![], vec![])
+LL +     l(vec![])
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/typeck/struct-enum-wrong-args.stderr b/tests/ui/typeck/struct-enum-wrong-args.stderr
index 57cbd1d2005..d005eca841e 100644
--- a/tests/ui/typeck/struct-enum-wrong-args.stderr
+++ b/tests/ui/typeck/struct-enum-wrong-args.stderr
@@ -2,13 +2,15 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
   --> $DIR/struct-enum-wrong-args.rs:6:13
    |
 LL |     let _ = Some(3, 2);
-   |             ^^^^  ---
-   |                   | |
-   |                   | unexpected argument of type `{integer}`
-   |                   help: remove the extra argument
+   |             ^^^^    - unexpected argument of type `{integer}`
    |
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
+help: remove the extra argument
+   |
+LL -     let _ = Some(3, 2);
+LL +     let _ = Some(3);
+   |
 
 error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied
   --> $DIR/struct-enum-wrong-args.rs:7:13
@@ -59,16 +61,18 @@ error[E0061]: this struct takes 1 argument but 2 arguments were supplied
   --> $DIR/struct-enum-wrong-args.rs:10:13
    |
 LL |     let _ = Wrapper(5, 2);
-   |             ^^^^^^^  ---
-   |                      | |
-   |                      | unexpected argument of type `{integer}`
-   |                      help: remove the extra argument
+   |             ^^^^^^^    - unexpected argument of type `{integer}`
    |
 note: tuple struct defined here
   --> $DIR/struct-enum-wrong-args.rs:2:8
    |
 LL | struct Wrapper(i32);
    |        ^^^^^^^
+help: remove the extra argument
+   |
+LL -     let _ = Wrapper(5, 2);
+LL +     let _ = Wrapper(5);
+   |
 
 error[E0061]: this struct takes 2 arguments but 0 arguments were supplied
   --> $DIR/struct-enum-wrong-args.rs:11:13
@@ -106,16 +110,18 @@ error[E0061]: this struct takes 2 arguments but 3 arguments were supplied
   --> $DIR/struct-enum-wrong-args.rs:13:13
    |
 LL |     let _ = DoubleWrapper(5, 2, 7);
-   |             ^^^^^^^^^^^^^     ---
-   |                               | |
-   |                               | unexpected argument of type `{integer}`
-   |                               help: remove the extra argument
+   |             ^^^^^^^^^^^^^       - unexpected argument of type `{integer}`
    |
 note: tuple struct defined here
   --> $DIR/struct-enum-wrong-args.rs:3:8
    |
 LL | struct DoubleWrapper(i32, i32);
    |        ^^^^^^^^^^^^^
+help: remove the extra argument
+   |
+LL -     let _ = DoubleWrapper(5, 2, 7);
+LL +     let _ = DoubleWrapper(5, 2);
+   |
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr
index c48d094daea..2a8c4edbdb5 100644
--- a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr
+++ b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr
@@ -2,10 +2,7 @@ error[E0053]: method `dummy2` has an incompatible type for trait
   --> $DIR/ufcs-explicit-self-bad.rs:37:21
    |
 LL |     fn dummy2(self: &Bar<T>) {}
-   |               ------^^^^^^^
-   |               |     |
-   |               |     expected `&'a Bar<T>`, found `Bar<T>`
-   |               help: change the self-receiver type to match the trait: `&self`
+   |                     ^^^^^^^ expected `&'a Bar<T>`, found `Bar<T>`
    |
 note: type in trait
   --> $DIR/ufcs-explicit-self-bad.rs:31:15
@@ -14,6 +11,10 @@ LL |     fn dummy2(&self);
    |               ^^^^^
    = note: expected signature `fn(&&'a Bar<_>)`
               found signature `fn(&Bar<_>)`
+help: change the self-receiver type to match the trait
+   |
+LL |     fn dummy2(&self) {}
+   |               ~~~~~
 
 error[E0307]: invalid `self` parameter type: `isize`
   --> $DIR/ufcs-explicit-self-bad.rs:8:18
diff --git a/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr b/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr
index ad5451ced55..04f9ab246b3 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr
@@ -1,73 +1,90 @@
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/unboxed-closure-immutable-capture.rs:9:13
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     move || x = 1;
    |             ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closure-immutable-capture.rs:10:17
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     move || x = 1;
 LL |     move || set(&mut x);
    |                 ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/unboxed-closure-immutable-capture.rs:11:13
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |     move || x = 1;
    |             ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closure-immutable-capture.rs:12:17
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |     move || set(&mut x);
    |                 ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/unboxed-closure-immutable-capture.rs:13:8
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |     || x = 1;
    |        ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closure-immutable-capture.rs:14:12
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |     || set(&mut x);
    |            ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/unboxed-closure-immutable-capture.rs:15:8
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |     || x = 1;
    |        ^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closure-immutable-capture.rs:16:12
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |     || set(&mut x);
    |            ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr
index 5c93ed6d7f7..07c66276eaf 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr
@@ -1,13 +1,16 @@
 error[E0596]: cannot borrow `tick1` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:16:9
    |
-LL |     let tick1 = || {
-   |         ----- help: consider changing this to be mutable: `mut tick1`
 LL |         counter += 1;
    |         ------- calling `tick1` requires mutable binding due to mutable borrow of `counter`
 ...
 LL |         tick1();
    |         ^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut tick1 = || {
+   |         +++
 
 error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:19:5
diff --git a/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
index 26f97b51913..80caddb2a11 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
@@ -1,29 +1,35 @@
 error[E0594]: cannot assign to `n`, as it is not declared as mutable
   --> $DIR/unboxed-closures-mutate-upvar.rs:15:9
    |
-LL |     let n = 0;
-   |         - help: consider changing this to be mutable: `mut n`
-LL |     let mut f = to_fn_mut(|| {
 LL |         n += 1;
    |         ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut n = 0;
+   |         +++
 
 error[E0594]: cannot assign to `n`, as it is not declared as mutable
   --> $DIR/unboxed-closures-mutate-upvar.rs:32:9
    |
-LL |     let n = 0;
-   |         - help: consider changing this to be mutable: `mut n`
-...
 LL |         n += 1;
    |         ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut n = 0;
+   |         +++
 
 error[E0594]: cannot assign to `n`, as it is not declared as mutable
   --> $DIR/unboxed-closures-mutate-upvar.rs:46:9
    |
-LL |     let n = 0;
-   |         - help: consider changing this to be mutable: `mut n`
-LL |     let mut f = to_fn(move || {
 LL |         n += 1;
    |         ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut n = 0;
+   |         +++
 
 error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure
   --> $DIR/unboxed-closures-mutate-upvar.rs:53:9
diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/expanded-interpolation.rs
index 8f0e21ce870..1dc72c67f51 100644
--- a/tests/ui/unpretty/expanded-interpolation.rs
+++ b/tests/ui/unpretty/expanded-interpolation.rs
@@ -18,6 +18,26 @@ macro_rules! stmt {
     ($stmt:stmt) => { $stmt };
 }
 
+fn break_labeled_loop() {
+    let no_paren = 'outer: loop {
+        break 'outer expr!('inner: loop { break 'inner 1; } + 1);
+    };
+
+    let paren_around_break_value = 'outer: loop {
+        break expr!('inner: loop { break 'inner 1; } + 1);
+    };
+
+    macro_rules! breaking {
+        ($value:expr) => {
+            break $value
+        };
+    }
+
+    let paren_around_break_value = loop {
+        breaking!('inner: loop { break 'inner 1; } + 1);
+    };
+}
+
 fn if_let() {
     macro_rules! if_let {
         ($pat:pat, $expr:expr) => {
diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout
index 73322b50f2d..556e57dbd92 100644
--- a/tests/ui/unpretty/expanded-interpolation.stdout
+++ b/tests/ui/unpretty/expanded-interpolation.stdout
@@ -20,6 +20,19 @@ macro_rules! expr { ($expr:expr) => { $expr }; }
 
 macro_rules! stmt { ($stmt:stmt) => { $stmt }; }
 
+fn break_labeled_loop() {
+    let no_paren =
+        'outer: loop { break 'outer 'inner: loop { break 'inner 1; } + 1; };
+
+    let paren_around_break_value =
+        'outer: loop { break ('inner: loop { break 'inner 1; } + 1); };
+
+    macro_rules! breaking { ($value:expr) => { break $value }; }
+
+    let paren_around_break_value =
+        loop { break ('inner: loop { break 'inner 1; } + 1); };
+}
+
 fn if_let() {
     macro_rules! if_let {
         ($pat:pat, $expr:expr) => { if let $pat = $expr {} };
diff --git a/tests/ui/unsafe/unsafe-fn-autoderef.stderr b/tests/ui/unsafe/unsafe-fn-autoderef.stderr
index c3ab8020222..c19028ac866 100644
--- a/tests/ui/unsafe/unsafe-fn-autoderef.stderr
+++ b/tests/ui/unsafe/unsafe-fn-autoderef.stderr
@@ -2,10 +2,12 @@ error[E0609]: no field `f` on type `*const Rec`
   --> $DIR/unsafe-fn-autoderef.rs:19:14
    |
 LL |     return p.f;
-   |            --^
-   |            | |
-   |            | unknown field
-   |            help: `p` is a raw pointer; try dereferencing it: `(*p).f`
+   |              ^ unknown field
+   |
+help: `p` is a raw pointer; try dereferencing it
+   |
+LL |     return (*p).f;
+   |            ++ +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/unsigned-literal-negation.stderr b/tests/ui/unsigned-literal-negation.stderr
index 0aaa8c3b72f..b0a730477a1 100644
--- a/tests/ui/unsigned-literal-negation.stderr
+++ b/tests/ui/unsigned-literal-negation.stderr
@@ -2,34 +2,37 @@ error[E0600]: cannot apply unary operator `-` to type `usize`
   --> $DIR/unsigned-literal-negation.rs:2:13
    |
 LL |     let x = -1 as usize;
-   |             ^^
-   |             |
-   |             cannot apply unary operator `-`
-   |             help: you may have meant the maximum value of `usize`: `usize::MAX`
+   |             ^^ cannot apply unary operator `-`
    |
    = note: unsigned values cannot be negated
+help: you may have meant the maximum value of `usize`
+   |
+LL |     let x = usize::MAX;
+   |             ~~~~~~~~~~
 
 error[E0600]: cannot apply unary operator `-` to type `usize`
   --> $DIR/unsigned-literal-negation.rs:3:13
    |
 LL |     let x = (-1) as usize;
-   |             ^^^^
-   |             |
-   |             cannot apply unary operator `-`
-   |             help: you may have meant the maximum value of `usize`: `usize::MAX`
+   |             ^^^^ cannot apply unary operator `-`
    |
    = note: unsigned values cannot be negated
+help: you may have meant the maximum value of `usize`
+   |
+LL |     let x = usize::MAX;
+   |             ~~~~~~~~~~
 
 error[E0600]: cannot apply unary operator `-` to type `u32`
   --> $DIR/unsigned-literal-negation.rs:4:18
    |
 LL |     let x: u32 = -1;
-   |                  ^^
-   |                  |
-   |                  cannot apply unary operator `-`
-   |                  help: you may have meant the maximum value of `u32`: `u32::MAX`
+   |                  ^^ cannot apply unary operator `-`
    |
    = note: unsigned values cannot be negated
+help: you may have meant the maximum value of `u32`
+   |
+LL |     let x: u32 = u32::MAX;
+   |                  ~~~~~~~~
 
 error: aborting due to 3 previous errors
 
diff --git a/triagebot.toml b/triagebot.toml
index 351ae1642f0..8767eb138a1 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -952,7 +952,6 @@ bootstrap = [
     "@Mark-Simulacrum",
     "@albertlarsan68",
     "@onur-ozkan",
-    "@clubby789",
     "@kobzol",
 ]
 infra-ci = [